From 639a20da908c2646de46b93ca2933651363ec22a Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Fri, 29 Apr 2016 17:39:33 +0100 Subject: [PATCH 001/267] syscall: simplify closing of extra fds in plan9 StartProcess Reviving earlier work by @ality in https://golang.org/cl/57890043 to make the closing of extra file descriptors in syscall.StartProcess less race-prone. Instead of making a list of open fds in the parent before forking, the child can read through the list of open fds and close the ones not explicitly requested. Also eliminate the complication of keeping open any extra fds which were inherited by the parent when it started. This CL will be followed by one to eliminate the ForkLock in plan9, which is now redundant. Fixes #5605 Change-Id: I6b4b942001baa54248b656c52dced3b62021c486 Reviewed-on: https://go-review.googlesource.com/22610 Run-TryBot: David du Colombier <0intro@gmail.com> Reviewed-by: David du Colombier <0intro@gmail.com> --- src/syscall/exec_plan9.go | 158 +++++++++++++++++++++-------------- src/syscall/syscall_plan9.go | 1 + 2 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go index bccea5105cb7bb..58e5a3c623b62a 100644 --- a/src/syscall/exec_plan9.go +++ b/src/syscall/exec_plan9.go @@ -61,6 +61,41 @@ import ( var ForkLock sync.RWMutex +// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order. +// It returns the string as a byte slice, or nil if b is too short to contain the length or +// the full string. +//go:nosplit +func gstringb(b []byte) []byte { + if len(b) < 2 { + return nil + } + n, b := gbit16(b) + if int(n) > len(b) { + return nil + } + return b[:n] +} + +// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go +const nameOffset = 39 + +// gdirname returns the first filename from a buffer of directory entries, +// and a slice containing the remaining directory entries. +// If the buffer doesn't start with a valid directory entry, the returned name is nil. +//go:nosplit +func gdirname(buf []byte) (name []byte, rest []byte) { + if len(buf) < 2 { + return + } + size, buf := gbit16(buf) + if size < STATFIXLEN || int(size) > len(buf) { + return + } + name = gstringb(buf[nameOffset:size]) + rest = buf[size:] + return +} + // StringSlicePtr converts a slice of strings to a slice of pointers // to NUL-terminated byte arrays. If any string contains a NUL byte // this function panics instead of returning an error. @@ -104,20 +139,13 @@ func readdirnames(dirfd int) (names []string, err error) { if n == 0 { break } - for i := 0; i < n; { - m, _ := gbit16(buf[i:]) - m += 2 - - if m < STATFIXLEN { + for b := buf[:n]; len(b) > 0; { + var s []byte + s, b = gdirname(b) + if s == nil { return nil, ErrBadStat } - - s, _, ok := gstring(buf[i+41:]) - if !ok { - return nil, ErrBadStat - } - names = append(names, s) - i += int(m) + names = append(names, string(s)) } } return @@ -152,16 +180,8 @@ func readdupdevice() (fds []int, err error) { return } -var startupFds []int - -// Plan 9 does not allow clearing the OCEXEC flag -// from the underlying channel backing an open file descriptor, -// therefore we store a list of already opened file descriptors -// inside startupFds and skip them when manually closing descriptors -// not meant to be passed to a child exec. -func init() { - startupFds, _ = readdupdevice() -} +// name of the directory containing names and control files for all open file descriptors +var dupdev, _ = BytePtrFromString("#d") // forkAndExecInChild forks the process, calling dup onto 0..len(fd) // and finally invoking exec(argv0, argvv, envv) in the child. @@ -174,7 +194,7 @@ func init() { // The calls to RawSyscall are okay because they are assembly // functions that do not grow the stack. //go:norace -func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err error) { +func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) { // Declare all variables at top in case any // declarations require heap allocation (e.g., errbuf). var ( @@ -184,6 +204,8 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at clearenv int envfd int errbuf [ERRMAX]byte + statbuf [STATMAX]byte + dupdevfd int ) // Guard against side effects of shuffling fds below. @@ -218,14 +240,39 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at // Fork succeeded, now in child. // Close fds we don't need. - for i = 0; i < len(fdsToClose); i++ { - if fdsToClose[i] != pipe { - RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0) + r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0) + dupdevfd = int(r1) + if dupdevfd == -1 { + goto childerror + } +dirloop: + for { + r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0) + n := int(r1) + switch n { + case -1: + goto childerror + case 0: + break dirloop + } + for b := statbuf[:n]; len(b) > 0; { + var s []byte + s, b = gdirname(b) + if s == nil { + copy(errbuf[:], ErrBadStat.Error()) + goto childerror1 + } + if s[len(s)-1] == 'l' { + // control file for descriptor is named ctl + continue + } + closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) } } + RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) + // Write new environment variables. if envv != nil { - // Write new environment variables. for i = 0; i < len(envv); i++ { r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) @@ -313,6 +360,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at childerror: // send error string on pipe RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0) +childerror1: errbuf[len(errbuf)-1] = 0 i = 0 for i < len(errbuf) && errbuf[i] != 0 { @@ -332,6 +380,20 @@ childerror: panic("unreached") } +// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. +//go:nosplit +func closeFdExcept(n int, fd1 int, fd2 int, fds []int) { + if n == fd1 || n == fd2 { + return + } + for _, fd := range fds { + if n == fd { + return + } + } + RawSyscall(SYS_CLOSE, uintptr(n), 0, 0) +} + func cexecPipe(p []int) error { e := Pipe(p) if e != nil { @@ -433,49 +495,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) // Acquire the fork lock to prevent other threads from creating new fds before we fork. ForkLock.Lock() - // get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child. - // no new fds can be created while we hold the ForkLock for writing. - openFds, e := readdupdevice() - if e != nil { - ForkLock.Unlock() - return 0, e - } - - fdsToClose := make([]int, 0, len(openFds)) - for _, fd := range openFds { - doClose := true - - // exclude files opened at startup. - for _, sfd := range startupFds { - if fd == sfd { - doClose = false - break - } - } - - // exclude files explicitly requested by the caller. - for _, rfd := range attr.Files { - if fd == int(rfd) { - doClose = false - break - } - } - - if doClose { - fdsToClose = append(fdsToClose, fd) - } - } - // Allocate child status pipe close on exec. - e = cexecPipe(p[:]) + e := cexecPipe(p[:]) if e != nil { return 0, e } - fdsToClose = append(fdsToClose, p[0]) // Kick off child. - pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork) + pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork) if err != nil { if p[0] >= 0 { @@ -493,8 +521,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) Close(p[0]) if err != nil || n != 0 { - if n != 0 { + if n > 0 { err = NewError(string(errbuf[:n])) + } else if err == nil { + err = NewError("failed to read exec status") } // Child failed; wait for it to exit, to make sure diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go index 796870825c98dc..b511867cda51d4 100644 --- a/src/syscall/syscall_plan9.go +++ b/src/syscall/syscall_plan9.go @@ -56,6 +56,7 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorSt func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) +//go:nosplit func atoi(b []byte) (n uint) { n = 0 for i := 0; i < len(b); i++ { From 5bf9b39acc7c4e9658190d8606b5d719678db14a Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Fri, 29 Apr 2016 21:02:59 +0100 Subject: [PATCH 002/267] os/exec: re-enable TestExtraFiles for plan9 This test should now succeed after CL 22610 which fixes issue #7118 Change-Id: Ie785a84d77b27c832a1ddd81699bf25dab24b97d Reviewed-on: https://go-review.googlesource.com/22640 Reviewed-by: Brad Fitzpatrick Reviewed-by: David du Colombier <0intro@gmail.com> Run-TryBot: David du Colombier <0intro@gmail.com> TryBot-Result: Gobot Gobot --- src/os/exec/exec_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 1151ca7d0f0c26..0cff3bb9264e7f 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -660,10 +660,6 @@ func TestHelperProcess(*testing.T) { // the cloned file descriptors that result from opening // /dev/urandom. // https://golang.org/issue/3955 - case "plan9": - // TODO(0intro): Determine why Plan 9 is leaking - // file descriptors. - // https://golang.org/issue/7118 case "solaris": // TODO(aram): This fails on Solaris because libc opens // its own files, as it sees fit. Darwin does the same, From 5f83bf6053763801beb84a926cde7221874bc4f7 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Thu, 5 May 2016 14:56:58 -0700 Subject: [PATCH 003/267] go/token: document postcondition of SetLines Change-Id: Ie163deade396b3e298a93845b9ca4d52333ea82a Reviewed-on: https://go-review.googlesource.com/22831 Reviewed-by: Brad Fitzpatrick --- src/go/token/position.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/go/token/position.go b/src/go/token/position.go index 33751779a3d9b5..7306083b0dd8ac 100644 --- a/src/go/token/position.go +++ b/src/go/token/position.go @@ -164,6 +164,7 @@ func (f *File) MergeLine(line int) { // Each line offset must be larger than the offset for the previous line // and smaller than the file size; otherwise SetLines fails and returns // false. +// Callers must not mutate the provided slice after SetLines returns. // func (f *File) SetLines(lines []int) bool { // verify validity of lines table From 6db98a3c51549eb5e1e481e9bca6ede7e8e15f54 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 5 May 2016 13:35:10 -0700 Subject: [PATCH 004/267] cmd/compile: repair MININT conversion bug in arm softfloat Negative-case conversion code was wrong for minimum int32, used negate-then-widen instead of widen-then-negate. Test already exists; this fixes the failure. Fixes #15563. Change-Id: I4b0b3ae8f2c9714bdcc405d4d0b1502ccfba2b40 Reviewed-on: https://go-review.googlesource.com/22830 Run-TryBot: David Chase Reviewed-by: Keith Randall TryBot-Result: Gobot Gobot --- src/runtime/softfloat_arm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go index 648b2e1169cffb..5f609c80d3ebae 100644 --- a/src/runtime/softfloat_arm.go +++ b/src/runtime/softfloat_arm.go @@ -530,7 +530,7 @@ execute: case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF) cmp := int32(m.freglo[regm]) if cmp < 0 { - fputf(regd, f64to32(fintto64(int64(-cmp)))) + fputf(regd, f64to32(fintto64(-int64(cmp)))) m.freglo[regd] ^= 0x80000000 } else { fputf(regd, f64to32(fintto64(int64(cmp)))) @@ -552,7 +552,7 @@ execute: case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD) cmp := int32(m.freglo[regm]) if cmp < 0 { - fputd(regd, fintto64(int64(-cmp))) + fputd(regd, fintto64(-int64(cmp))) m.freghi[regd] ^= 0x80000000 } else { fputd(regd, fintto64(int64(cmp))) From acc757f678a42ba1ffbf8bb9886de4fe080302de Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Tue, 5 Apr 2016 11:22:53 -0700 Subject: [PATCH 005/267] all: use SeekStart, SeekCurrent, SeekEnd CL/19862 (f79b50b8d5bc159561c1dcf7c17e2a0db96a9a11) recently introduced the constants SeekStart, SeekCurrent, and SeekEnd to the io package. We should use these constants consistently throughout the code base. Updates #15269 Change-Id: If7fcaca7676e4a51f588528f5ced28220d9639a2 Reviewed-on: https://go-review.googlesource.com/22097 Reviewed-by: Brad Fitzpatrick Run-TryBot: Joe Tsai TryBot-Result: Gobot Gobot --- src/bufio/bufio_test.go | 2 +- src/bytes/reader.go | 6 +++--- src/bytes/reader_test.go | 2 +- src/cmd/go/note.go | 2 +- src/cmd/internal/goobj/read.go | 8 ++++---- src/cmd/pack/pack.go | 4 ++-- src/debug/elf/file_test.go | 8 ++++---- src/debug/elf/reader.go | 6 +++--- src/go/internal/gccgoimporter/importer.go | 4 ++-- src/io/example_test.go | 2 +- src/io/io.go | 6 +++--- src/io/io_test.go | 4 ++-- src/net/file_plan9.go | 2 +- src/net/http/internal/chunked_test.go | 2 +- src/net/lookup_plan9.go | 5 +++-- src/os/file_plan9.go | 3 ++- src/os/file_windows.go | 8 ++++---- src/os/os_test.go | 18 +++++++++--------- src/runtime/runtime-lldb_test.go | 4 ++-- src/strings/reader.go | 6 +++--- src/strings/strings_test.go | 2 +- src/syscall/fd_nacl.go | 7 ++++--- src/syscall/fs_nacl.go | 5 +++-- src/syscall/syscall_unix_test.go | 5 +++-- src/time/sys_plan9.go | 5 +++-- src/time/sys_unix.go | 5 +++-- src/time/sys_windows.go | 5 +++-- 27 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go index d769a6aaa98d0e..858048696e4ed1 100644 --- a/src/bufio/bufio_test.go +++ b/src/bufio/bufio_test.go @@ -1475,7 +1475,7 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) { b.Fatal("ioutil.Discard doesn't support ReaderFrom") } for i := 0; i < b.N; i++ { - r.Seek(0, 0) + r.Seek(0, io.SeekStart) srcReader.Reset(onlyReader{r}) n, err := srcReader.WriteTo(ioutil.Discard) if err != nil { diff --git a/src/bytes/reader.go b/src/bytes/reader.go index 83826c80c417af..28cfc7a97884a7 100644 --- a/src/bytes/reader.go +++ b/src/bytes/reader.go @@ -108,11 +108,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { r.prevRune = -1 var abs int64 switch whence { - case 0: + case io.SeekStart: abs = offset - case 1: + case io.SeekCurrent: abs = r.i + offset - case 2: + case io.SeekEnd: abs = int64(len(r.s)) + offset default: return 0, errors.New("bytes.Reader.Seek: invalid whence") diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go index b5c78506189e50..7b3034d4e0d90c 100644 --- a/src/bytes/reader_test.go +++ b/src/bytes/reader_test.go @@ -188,7 +188,7 @@ var UnreadRuneErrorTests = []struct { {"Read", func(r *Reader) { r.Read([]byte{0}) }}, {"ReadByte", func(r *Reader) { r.ReadByte() }}, {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, - {"Seek", func(r *Reader) { r.Seek(0, 1) }}, + {"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }}, {"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }}, } diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go index ada8ddded47f28..fae9536d13fb93 100644 --- a/src/cmd/go/note.go +++ b/src/cmd/go/note.go @@ -110,7 +110,7 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, // or even the first few megabytes of the file // due to differences in note segment placement; // in that case, extract the note data manually. - _, err = f.Seek(int64(p.Off), 0) + _, err = f.Seek(int64(p.Off), io.SeekStart) if err != nil { return "", err } diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go index 69fa496110db43..214f65cbc4cbdf 100644 --- a/src/cmd/internal/goobj/read.go +++ b/src/cmd/internal/goobj/read.go @@ -290,9 +290,9 @@ func importPathToPrefix(s string) string { func (r *objReader) init(f io.ReadSeeker, p *Package) { r.f = f r.p = p - r.offset, _ = f.Seek(0, 1) - r.limit, _ = f.Seek(0, 2) - f.Seek(r.offset, 0) + r.offset, _ = f.Seek(0, io.SeekCurrent) + r.limit, _ = f.Seek(0, io.SeekEnd) + f.Seek(r.offset, io.SeekStart) r.b = bufio.NewReader(f) r.pkgprefix = importPathToPrefix(p.ImportPath) + "." } @@ -440,7 +440,7 @@ func (r *objReader) skip(n int64) { r.readFull(r.tmp[:n]) } else { // Seek, giving up buffered data. - _, err := r.f.Seek(r.offset+n, 0) + _, err := r.f.Seek(r.offset+n, io.SeekStart) if err != nil { r.error(err) } diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go index 5be42555d08118..1c168f946bd04e 100644 --- a/src/cmd/pack/pack.go +++ b/src/cmd/pack/pack.go @@ -286,7 +286,7 @@ func (ar *Archive) output(entry *Entry, w io.Writer) { log.Fatal("short file") } if entry.size&1 == 1 { - _, err := ar.fd.Seek(1, 1) + _, err := ar.fd.Seek(1, io.SeekCurrent) if err != nil { log.Fatal(err) } @@ -299,7 +299,7 @@ func (ar *Archive) skip(entry *Entry) { if size&1 == 1 { size++ } - _, err := ar.fd.Seek(size, 1) + _, err := ar.fd.Seek(size, io.SeekCurrent) if err != nil { log.Fatal(err) } diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go index 2fe6febb26b024..b189219a556a21 100644 --- a/src/debug/elf/file_test.go +++ b/src/debug/elf/file_test.go @@ -655,7 +655,7 @@ func TestCompressedSection(t *testing.T) { // Test Open method and seeking. buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0 sf := sec.Open() - if got, err := sf.Seek(0, 2); got != int64(len(b)) || err != nil { + if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil { t.Fatalf("want seek end %d, got %d error %v", len(b), got, err) } if n, err := sf.Read(buf); n != 0 || err != io.EOF { @@ -668,11 +668,11 @@ func TestCompressedSection(t *testing.T) { target := rand.Int63n(int64(len(buf))) var offset int64 switch whence { - case 0: + case io.SeekStart: offset = target - case 1: + case io.SeekCurrent: offset = target - pos - case 2: + case io.SeekEnd: offset = target - int64(len(buf)) } pos, err = sf.Seek(offset, whence) diff --git a/src/debug/elf/reader.go b/src/debug/elf/reader.go index 4dac6d1b2973c5..eab437318d6d3e 100644 --- a/src/debug/elf/reader.go +++ b/src/debug/elf/reader.go @@ -63,11 +63,11 @@ func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { var newOffset int64 switch whence { - case 0: + case io.SeekStart: newOffset = offset - case 1: + case io.SeekCurrent: newOffset = r.offset + offset - case 2: + case io.SeekEnd: newOffset = r.size + offset default: return 0, os.ErrInvalid diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go index aa0d01afdf3826..65cc2df6860515 100644 --- a/src/go/internal/gccgoimporter/importer.go +++ b/src/go/internal/gccgoimporter/importer.go @@ -90,7 +90,7 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e } // reset to offset 0 - needed on Plan 9 (see issue #11265) // TODO: remove once issue #11265 has been resolved. - _, err = f.Seek(0, 0) + _, err = f.Seek(0, io.SeekStart) if err != nil { return } @@ -168,7 +168,7 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo if err != nil { return } - _, err = reader.Seek(0, 0) + _, err = reader.Seek(0, io.SeekStart) if err != nil { return } diff --git a/src/io/example_test.go b/src/io/example_test.go index 412dfb3b921ba4..bf16de8fe2357d 100644 --- a/src/io/example_test.go +++ b/src/io/example_test.go @@ -189,7 +189,7 @@ func ExampleSectionReader_Seek() { r := strings.NewReader("some io.Reader stream to be read\n") s := io.NewSectionReader(r, 5, 16) - if _, err := s.Seek(10, 0); err != nil { + if _, err := s.Seek(10, io.SeekStart); err != nil { log.Fatal(err) } diff --git a/src/io/io.go b/src/io/io.go index c36ec2afbb0915..3d0a5a485e69b7 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -480,11 +480,11 @@ func (s *SectionReader) Seek(offset int64, whence int) (int64, error) { switch whence { default: return 0, errWhence - case 0: + case SeekStart: offset += s.base - case 1: + case SeekCurrent: offset += s.off - case 2: + case SeekEnd: offset += s.limit } if offset < s.base { diff --git a/src/io/io_test.go b/src/io/io_test.go index e892574b0b5f2e..877e8392e279a0 100644 --- a/src/io/io_test.go +++ b/src/io/io_test.go @@ -347,7 +347,7 @@ func TestSectionReader_Seek(t *testing.T) { br := bytes.NewReader([]byte("foo")) sr := NewSectionReader(br, 0, int64(len("foo"))) - for whence := 0; whence <= 2; whence++ { + for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} { for offset := int64(-3); offset <= 4; offset++ { brOff, brErr := br.Seek(offset, whence) srOff, srErr := sr.Seek(offset, whence) @@ -359,7 +359,7 @@ func TestSectionReader_Seek(t *testing.T) { } // And verify we can just seek past the end and get an EOF - got, err := sr.Seek(100, 0) + got, err := sr.Seek(100, SeekStart) if err != nil || got != 100 { t.Errorf("Seek = %v, %v; want 100, nil", got, err) } diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go index 892775a024f456..24efdc5186d89f 100644 --- a/src/net/file_plan9.go +++ b/src/net/file_plan9.go @@ -60,7 +60,7 @@ func newFileFD(f *os.File) (net *netFD, err error) { dir := netdir + "/" + comp[n-2] ctl = os.NewFile(uintptr(fd), dir+"/"+file) - ctl.Seek(0, 0) + ctl.Seek(0, io.SeekStart) var buf [16]byte n, err := ctl.Read(buf[:]) if err != nil { diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go index a136dc99a65fc8..9abe1ab6d9d674 100644 --- a/src/net/http/internal/chunked_test.go +++ b/src/net/http/internal/chunked_test.go @@ -122,7 +122,7 @@ func TestChunkReaderAllocs(t *testing.T) { byter := bytes.NewReader(buf.Bytes()) bufr := bufio.NewReader(byter) mallocs := testing.AllocsPerRun(100, func() { - byter.Seek(0, 0) + byter.Seek(0, io.SeekStart) bufr.Reset(byter) r := NewChunkedReader(bufr) n, err := io.ReadFull(r, readBuf) diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go index 73147a2d3f7c40..3f7af2a1747c32 100644 --- a/src/net/lookup_plan9.go +++ b/src/net/lookup_plan9.go @@ -7,6 +7,7 @@ package net import ( "context" "errors" + "io" "os" ) @@ -17,7 +18,7 @@ func query(ctx context.Context, filename, query string, bufSize int) (res []stri } defer file.Close() - _, err = file.Seek(0, 0) + _, err = file.Seek(0, io.SeekStart) if err != nil { return } @@ -25,7 +26,7 @@ func query(ctx context.Context, filename, query string, bufSize int) (res []stri if err != nil { return } - _, err = file.Seek(0, 0) + _, err = file.Seek(0, io.SeekStart) if err != nil { return } diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go index 0fe1b8213dc54b..fb796a2a89bcba 100644 --- a/src/os/file_plan9.go +++ b/src/os/file_plan9.go @@ -5,6 +5,7 @@ package os import ( + "io" "runtime" "syscall" "time" @@ -123,7 +124,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) { } if append { - if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil { + if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil { return nil, &PathError{"seek", name, e} } } diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 137f24a0a95979..08aff83a77510c 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -325,11 +325,11 @@ func (f *File) read(b []byte) (n int, err error) { func (f *File) pread(b []byte, off int64) (n int, err error) { f.l.Lock() defer f.l.Unlock() - curoffset, e := syscall.Seek(f.fd, 0, 1) + curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent) if e != nil { return 0, e } - defer syscall.Seek(f.fd, curoffset, 0) + defer syscall.Seek(f.fd, curoffset, io.SeekStart) o := syscall.Overlapped{ OffsetHigh: uint32(off >> 32), Offset: uint32(off), @@ -405,11 +405,11 @@ func (f *File) write(b []byte) (n int, err error) { func (f *File) pwrite(b []byte, off int64) (n int, err error) { f.l.Lock() defer f.l.Unlock() - curoffset, e := syscall.Seek(f.fd, 0, 1) + curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent) if e != nil { return 0, e } - defer syscall.Seek(f.fd, curoffset, 0) + defer syscall.Seek(f.fd, curoffset, io.SeekStart) o := syscall.Overlapped{ OffsetHigh: uint32(off >> 32), Offset: uint32(off), diff --git a/src/os/os_test.go b/src/os/os_test.go index 8f62902a6caaf8..de25f26614d452 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1182,14 +1182,14 @@ func TestSeek(t *testing.T) { out int64 } var tests = []test{ - {0, 1, int64(len(data))}, - {0, 0, 0}, - {5, 0, 5}, - {0, 2, int64(len(data))}, - {0, 0, 0}, - {-1, 2, int64(len(data)) - 1}, - {1 << 33, 0, 1 << 33}, - {1 << 33, 2, 1<<33 + int64(len(data))}, + {0, io.SeekCurrent, int64(len(data))}, + {0, io.SeekStart, 0}, + {5, io.SeekStart, 5}, + {0, io.SeekEnd, int64(len(data))}, + {0, io.SeekStart, 0}, + {-1, io.SeekEnd, int64(len(data)) - 1}, + {1 << 33, io.SeekStart, 1 << 33}, + {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, } for i, tt := range tests { off, err := f.Seek(tt.in, tt.whence) @@ -1726,7 +1726,7 @@ var nilFileMethodTests = []struct { {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, - {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }}, + {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }}, {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, {"Sync", func(f *File) error { return f.Sync() }}, {"Truncate", func(f *File) error { return f.Truncate(0) }}, diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go index 2bd91c1ec03893..4c379b9cdc28b7 100644 --- a/src/runtime/runtime-lldb_test.go +++ b/src/runtime/runtime-lldb_test.go @@ -232,7 +232,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) SegmentSize uint8 } for { - offset, err := data.Seek(0, 1) + offset, err := data.Seek(0, io.SeekCurrent) if err != nil { t.Fatalf("Seek error: %v", err) } @@ -246,7 +246,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) if lastTupleOffset%tupleSize != 0 { t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize) } - if _, err = data.Seek(lastTupleOffset, 0); err != nil { + if _, err = data.Seek(lastTupleOffset, io.SeekStart); err != nil { t.Fatalf("Seek error: %v", err) } buf := make([]byte, tupleSize) diff --git a/src/strings/reader.go b/src/strings/reader.go index e254837c63b96a..6c1a5064c0d5ef 100644 --- a/src/strings/reader.go +++ b/src/strings/reader.go @@ -107,11 +107,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { r.prevRune = -1 var abs int64 switch whence { - case 0: + case io.SeekStart: abs = offset - case 1: + case io.SeekCurrent: abs = r.i + offset - case 2: + case io.SeekEnd: abs = int64(len(r.s)) + offset default: return 0, errors.New("strings.Reader.Seek: invalid whence") diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index 1ed803bf8502e7..d92dfcc8742b27 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -952,7 +952,7 @@ var UnreadRuneErrorTests = []struct { {"Read", func(r *Reader) { r.Read([]byte{0}) }}, {"ReadByte", func(r *Reader) { r.ReadByte() }}, {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, - {"Seek", func(r *Reader) { r.Seek(0, 1) }}, + {"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }}, {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }}, } diff --git a/src/syscall/fd_nacl.go b/src/syscall/fd_nacl.go index 715992b1bfc684..e559793c8b80e7 100644 --- a/src/syscall/fd_nacl.go +++ b/src/syscall/fd_nacl.go @@ -10,6 +10,7 @@ package syscall import ( + "io" "sync" ) @@ -252,15 +253,15 @@ func (f *naclFile) seek(off int64, whence int) (int64, error) { func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) { // NaCl has no pread; simulate with seek and hope for no races. - old, err := f.seek(0, 1) + old, err := f.seek(0, io.SeekCurrent) if err != nil { return 0, err } - if _, err := f.seek(offset, 0); err != nil { + if _, err := f.seek(offset, io.SeekStart); err != nil { return 0, err } n, err := rw(b) - f.seek(old, 0) + f.seek(old, io.SeekStart) return n, err } diff --git a/src/syscall/fs_nacl.go b/src/syscall/fs_nacl.go index 4019fad1a5d1e6..cbd9539c92cab3 100644 --- a/src/syscall/fs_nacl.go +++ b/src/syscall/fs_nacl.go @@ -15,6 +15,7 @@ package syscall import ( + "io" "sync" "unsafe" ) @@ -367,9 +368,9 @@ func (f *fsysFile) seek(offset int64, whence int) (int64, error) { f.fsys.mu.Lock() defer f.fsys.mu.Unlock() switch whence { - case 1: + case io.SeekCurrent: offset += f.offset - case 2: + case io.SeekEnd: offset += f.inode.Size } if offset < 0 { diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go index c7b4560b76bc5e..80544f331923d6 100644 --- a/src/syscall/syscall_unix_test.go +++ b/src/syscall/syscall_unix_test.go @@ -10,6 +10,7 @@ import ( "flag" "fmt" "internal/testenv" + "io" "io/ioutil" "net" "os" @@ -244,7 +245,7 @@ func passFDChild() { } f.Write([]byte("Hello from child process!\n")) - f.Seek(0, 0) + f.Seek(0, io.SeekStart) rights := syscall.UnixRights(int(f.Fd())) dummyByte := []byte("x") @@ -344,7 +345,7 @@ func TestRlimit(t *testing.T) { } func TestSeekFailure(t *testing.T) { - _, err := syscall.Seek(-1, 0, 0) + _, err := syscall.Seek(-1, 0, io.SeekStart) if err == nil { t.Fatalf("Seek(-1, 0, 0) did not fail") } diff --git a/src/time/sys_plan9.go b/src/time/sys_plan9.go index 8484729448eb96..507d1159cfe9d5 100644 --- a/src/time/sys_plan9.go +++ b/src/time/sys_plan9.go @@ -8,6 +8,7 @@ package time import ( "errors" + "io" "syscall" ) @@ -55,9 +56,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 + whence := io.SeekStart if off < 0 { - whence = 2 + whence = io.SeekEnd } if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { return err diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go index e592415daa5161..dea03e06d51cf9 100644 --- a/src/time/sys_unix.go +++ b/src/time/sys_unix.go @@ -8,6 +8,7 @@ package time import ( "errors" + "io" "syscall" ) @@ -55,9 +56,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 + whence := io.SeekStart if off < 0 { - whence = 2 + whence = io.SeekEnd } if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { return err diff --git a/src/time/sys_windows.go b/src/time/sys_windows.go index de63b4bf4bb87b..4f41b1a7a3c64d 100644 --- a/src/time/sys_windows.go +++ b/src/time/sys_windows.go @@ -6,6 +6,7 @@ package time import ( "errors" + "io" "syscall" ) @@ -52,9 +53,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 + whence := io.SeekStart if off < 0 { - whence = 2 + whence = io.SeekEnd } if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil { return err From a633d766d1763f4f4648e423c4e8a8635b183d03 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 6 May 2016 08:51:16 +0900 Subject: [PATCH 006/267] Revert "net: add support for Zone of IPNet" Updates #14518. This reverts commit 3e9264c9ae781a2cd28127deaed6ae26f84b4b15. Change-Id: I2531b04efc735b5b51ef675541172f2f5ae747d9 Reviewed-on: https://go-review.googlesource.com/22836 Reviewed-by: Mikio Hara Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/interface_bsd.go | 1 - src/net/interface_linux.go | 3 --- src/net/interface_test.go | 6 +----- src/net/interface_windows.go | 3 --- src/net/ip.go | 14 ++++---------- src/net/ip_test.go | 8 -------- 6 files changed, 5 insertions(+), 30 deletions(-) diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 98d19f2d33d42f..17c6dd3dcd69df 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -166,7 +166,6 @@ func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) { // link-local address as the kernel-internal form. if ifa.IP.IsLinkLocalUnicast() { ifa.IP[2], ifa.IP[3] = 0, 0 - ifa.Zone = ifi.Name } } if ifa.IP == nil || ifa.Mask == nil { diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go index b8f57fd7db39f0..5e391b28b0f8c4 100644 --- a/src/net/interface_linux.go +++ b/src/net/interface_linux.go @@ -193,9 +193,6 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou case syscall.AF_INET6: ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)} copy(ifa.IP, a.Value[:]) - if ifa.IP.IsLinkLocalUnicast() { - ifa.Zone = ifi.Name - } return ifa } } diff --git a/src/net/interface_test.go b/src/net/interface_test.go index c3e1ee231ffce9..e1580134937de0 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -221,10 +221,6 @@ func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) { t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen) continue } - if ifa.IP.IsLinkLocalUnicast() && ifa.Zone == "" { - t.Errorf("no IPv6 zone identifier found: %#v", ifa) - continue - } naf6++ } t.Logf("interface address %q", ifa.String()) @@ -243,7 +239,7 @@ func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) { if ifa.IP.To16() != nil && ifa.IP.To4() == nil { naf6++ } - t.Logf("interface address %q", ifa.String()) + t.Logf("interface address %s", ifa.String()) default: t.Errorf("unexpected type: %T", ifa) } diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go index 69de095e667d8c..8b976e585f36aa 100644 --- a/src/net/interface_windows.go +++ b/src/net/interface_windows.go @@ -159,9 +159,6 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { } ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)} copy(ifa.IP, sa.Addr[:]) - if ifa.IP.IsLinkLocalUnicast() { - ifa.Zone = syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:]) - } ifat = append(ifat, ifa) } } diff --git a/src/net/ip.go b/src/net/ip.go index e8b0fd990bf896..a2361bbdbfc132 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -36,7 +36,6 @@ type IPMask []byte type IPNet struct { IP IP // network number Mask IPMask // network mask - Zone string // IPv6 scoped addressing zone } // IPv4 returns the IP address (in 16-byte form) of the @@ -495,15 +494,11 @@ func (n *IPNet) String() string { if nn == nil || m == nil { return "" } - ip := nn.String() - if n.Zone != "" { - ip = ip + "%" + n.Zone - } l := simpleMaskLength(m) if l == -1 { - return ip + "/" + m.String() + return nn.String() + "/" + m.String() } - return ip + "/" + uitoa(uint(l)) + return nn.String() + "/" + uitoa(uint(l)) } // Parse IPv4 address (d.d.d.d). @@ -675,18 +670,17 @@ func ParseCIDR(s string) (IP, *IPNet, error) { if i < 0 { return nil, nil, &ParseError{Type: "CIDR address", Text: s} } - var zone string addr, mask := s[:i], s[i+1:] iplen := IPv4len ip := parseIPv4(addr) if ip == nil { iplen = IPv6len - ip, zone = parseIPv6(addr, true) + ip, _ = parseIPv6(addr, false) } n, i, ok := dtoi(mask, 0) if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen { return nil, nil, &ParseError{Type: "CIDR address", Text: s} } m := CIDRMask(n, 8*iplen) - return ip, &IPNet{IP: ip.Mask(m), Mask: m, Zone: zone}, nil + return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil } diff --git a/src/net/ip_test.go b/src/net/ip_test.go index 1d67057d6afbbc..87c12133c33567 100644 --- a/src/net/ip_test.go +++ b/src/net/ip_test.go @@ -327,9 +327,6 @@ var parseCIDRTests = []struct { {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil}, {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil}, {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil}, - {"fe80::%en0/64", ParseIP("fe80::"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil}, - {"fe80::1%en0/64", ParseIP("fe80::1"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil}, - {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}}, {"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}}, {"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}}, @@ -376,13 +373,8 @@ var ipNetStringTests = []struct { out string }{ {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"}, - {&IPNet{IP: IPv4(192, 168, 1, 1), Mask: CIDRMask(26, 32)}, "192.168.1.1/26"}, {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"}, - {&IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::%en0/64"}, - {&IPNet{IP: ParseIP("fe80::1"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::1%en0/64"}, - {&IPNet{IP: ParseIP("fe80::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::")), Zone: "en0"}, "fe80::%en0/8000f1230000cafe0000000000000000"}, {&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"}, - {&IPNet{IP: ParseIP("2001:db8::1"), Mask: CIDRMask(55, 128)}, "2001:db8::1/55"}, {&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"}, } From 88d3db0a5b5196ed45c96014d5a2d32e4e41e34e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Jan 2016 12:45:23 -0500 Subject: [PATCH 007/267] runtime: stop traceback at foreign function This can only happen when profiling and there is foreign code at the top of the g0 stack but we're not in cgo. That in turn only happens with the race detector. Fixes #13568. Change-Id: I23775132c9c1a3a3aaae191b318539f368adf25e Reviewed-on: https://go-review.googlesource.com/18322 Reviewed-by: Ian Lance Taylor Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/traceback.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 7771426ef95e97..0e96a28945351b 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -241,6 +241,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // stk is the stack containing sp. // The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp. f = frame.fn + if f.pcsp == 0 { + // No frame information, must be external function, like race support. + // See golang.org/issue/13568. + break + } // Found an actual function. // Derive frame pointer and link register. From 30bfafc319288e8cfe54111664e3f2f259998a0a Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Thu, 17 Sep 2015 00:22:56 -0700 Subject: [PATCH 008/267] archive/tar: centralize all information about tar header format The Reader and Writer have hard-coded constants regarding the offsets and lengths of certain fields in the tar format sprinkled all over. This makes it harder to verify that the offsets are correct since a reviewer would need to search for them throughout the code. Instead, all information about the layout of header fields should be centralized in one single file. This has the advantage of being both centralized, and also acting as a form of documentation about the header struct format. This method was chosen over using "encoding/binary" since that method would cause an allocation of a header struct every time binary.Read was called. This method causes zero allocations and its logic is no longer than if structs were declared. Updates #12594 Change-Id: Ic7a0565d2a2cd95d955547ace3b6dea2b57fab34 Reviewed-on: https://go-review.googlesource.com/14669 Reviewed-by: Brad Fitzpatrick --- src/archive/tar/common.go | 37 +------ src/archive/tar/format.go | 197 +++++++++++++++++++++++++++++++++ src/archive/tar/reader.go | 167 +++++++++++----------------- src/archive/tar/writer.go | 100 +++++++---------- src/archive/tar/writer_test.go | 22 ++-- 5 files changed, 314 insertions(+), 209 deletions(-) create mode 100644 src/archive/tar/format.go diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go index 36f4e23980930c..2a1e4321826195 100644 --- a/src/archive/tar/common.go +++ b/src/archive/tar/common.go @@ -21,10 +21,8 @@ import ( "time" ) +// Header type flags. const ( - blockSize = 512 - - // Types TypeReg = '0' // regular file TypeRegA = '\x00' // regular file TypeLink = '1' // hard link @@ -61,12 +59,6 @@ type Header struct { Xattrs map[string]string } -// File name constants from the tar spec. -const ( - fileNameSize = 100 // Maximum number of bytes in a standard tar name. - fileNamePrefixSize = 155 // Maximum number of ustar extension bytes. -) - // FileInfo returns an os.FileInfo for the Header. func (h *Header) FileInfo() os.FileInfo { return headerFileInfo{h} @@ -279,33 +271,6 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { return h, nil } -var zeroBlock = make([]byte, blockSize) - -// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values. -// We compute and return both. -func checksum(header []byte) (unsigned int64, signed int64) { - for i := 0; i < len(header); i++ { - if i == 148 { - // The chksum field (header[148:156]) is special: it should be treated as space bytes. - unsigned += ' ' * 8 - signed += ' ' * 8 - i += 7 - continue - } - unsigned += int64(header[i]) - signed += int64(int8(header[i])) - } - return -} - -type slicer []byte - -func (sp *slicer) next(n int) (b []byte) { - s := *sp - b, *sp = s[0:n], s[n:] - return -} - func isASCII(s string) bool { for _, c := range s { if c >= 0x80 { diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go new file mode 100644 index 00000000000000..c2c9910d00281f --- /dev/null +++ b/src/archive/tar/format.go @@ -0,0 +1,197 @@ +// 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 tar + +// Constants to identify various tar formats. +const ( + // The format is unknown. + formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc... + + // The format of the original Unix V7 tar tool prior to standardization. + formatV7 + + // The old and new GNU formats, which are incompatible with USTAR. + // This does cover the old GNU sparse extension. + // This does not cover the GNU sparse extensions using PAX headers, + // versions 0.0, 0.1, and 1.0; these fall under the PAX format. + formatGNU + + // Schily's tar format, which is incompatible with USTAR. + // This does not cover STAR extensions to the PAX format; these fall under + // the PAX format. + formatSTAR + + // USTAR is the former standardization of tar defined in POSIX.1-1988. + // This is incompatible with the GNU and STAR formats. + formatUSTAR + + // PAX is the latest standardization of tar defined in POSIX.1-2001. + // This is an extension of USTAR and is "backwards compatible" with it. + // + // Some newer formats add their own extensions to PAX, such as GNU sparse + // files and SCHILY extended attributes. Since they are backwards compatible + // with PAX, they will be labelled as "PAX". + formatPAX +) + +// Magics used to identify various formats. +const ( + magicGNU, versionGNU = "ustar ", " \x00" + magicUSTAR, versionUSTAR = "ustar\x00", "00" + trailerSTAR = "tar\x00" +) + +// Size constants from various tar specifications. +const ( + blockSize = 512 // Size of each block in a tar stream + nameSize = 100 // Max length of the name field in USTAR format + prefixSize = 155 // Max length of the prefix field in USTAR format +) + +var zeroBlock block + +type block [blockSize]byte + +// Convert block to any number of formats. +func (b *block) V7() *headerV7 { return (*headerV7)(b) } +func (b *block) GNU() *headerGNU { return (*headerGNU)(b) } +func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) } +func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) } +func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) } + +// GetFormat checks that the block is a valid tar header based on the checksum. +// It then attempts to guess the specific format based on magic values. +// If the checksum fails, then formatUnknown is returned. +func (b *block) GetFormat() (format int) { + // Verify checksum. + var p parser + value := p.parseOctal(b.V7().Chksum()) + chksum1, chksum2 := b.ComputeChecksum() + if p.err != nil || (value != chksum1 && value != chksum2) { + return formatUnknown + } + + // Guess the magic values. + magic := string(b.USTAR().Magic()) + version := string(b.USTAR().Version()) + trailer := string(b.STAR().Trailer()) + switch { + case magic == magicUSTAR && trailer == trailerSTAR: + return formatSTAR + case magic == magicUSTAR: + return formatUSTAR + case magic == magicGNU && version == versionGNU: + return formatGNU + default: + return formatV7 + } +} + +// SetFormat writes the magic values necessary for specified format +// and then updates the checksum accordingly. +func (b *block) SetFormat(format int) { + // Set the magic values. + switch format { + case formatV7: + // Do nothing. + case formatGNU: + copy(b.GNU().Magic(), magicGNU) + copy(b.GNU().Version(), versionGNU) + case formatSTAR: + copy(b.STAR().Magic(), magicUSTAR) + copy(b.STAR().Version(), versionUSTAR) + copy(b.STAR().Trailer(), trailerSTAR) + case formatUSTAR, formatPAX: + copy(b.USTAR().Magic(), magicUSTAR) + copy(b.USTAR().Version(), versionUSTAR) + default: + panic("invalid format") + } + + // Update checksum. + // This field is special in that it is terminated by a NULL then space. + var f formatter + field := b.V7().Chksum() + chksum, _ := b.ComputeChecksum() // Possible values are 256..128776 + f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143 + field[7] = ' ' +} + +// ComputeChecksum computes the checksum for the header block. +// POSIX specifies a sum of the unsigned byte values, but the Sun tar used +// signed byte values. +// We compute and return both. +func (b *block) ComputeChecksum() (unsigned, signed int64) { + for i, c := range b { + if 148 <= i && i < 156 { + c = ' ' // Treat the checksum field itself as all spaces. + } + unsigned += int64(uint8(c)) + signed += int64(int8(c)) + } + return unsigned, signed +} + +type headerV7 [blockSize]byte + +func (h *headerV7) Name() []byte { return h[000:][:100] } +func (h *headerV7) Mode() []byte { return h[100:][:8] } +func (h *headerV7) UID() []byte { return h[108:][:8] } +func (h *headerV7) GID() []byte { return h[116:][:8] } +func (h *headerV7) Size() []byte { return h[124:][:12] } +func (h *headerV7) ModTime() []byte { return h[136:][:12] } +func (h *headerV7) Chksum() []byte { return h[148:][:8] } +func (h *headerV7) TypeFlag() []byte { return h[156:][:1] } +func (h *headerV7) LinkName() []byte { return h[157:][:100] } + +type headerGNU [blockSize]byte + +func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) } +func (h *headerGNU) Magic() []byte { return h[257:][:6] } +func (h *headerGNU) Version() []byte { return h[263:][:2] } +func (h *headerGNU) UserName() []byte { return h[265:][:32] } +func (h *headerGNU) GroupName() []byte { return h[297:][:32] } +func (h *headerGNU) DevMajor() []byte { return h[329:][:8] } +func (h *headerGNU) DevMinor() []byte { return h[337:][:8] } +func (h *headerGNU) AccessTime() []byte { return h[345:][:12] } +func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] } +func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) } +func (h *headerGNU) RealSize() []byte { return h[483:][:12] } + +type headerSTAR [blockSize]byte + +func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) } +func (h *headerSTAR) Magic() []byte { return h[257:][:6] } +func (h *headerSTAR) Version() []byte { return h[263:][:2] } +func (h *headerSTAR) UserName() []byte { return h[265:][:32] } +func (h *headerSTAR) GroupName() []byte { return h[297:][:32] } +func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] } +func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] } +func (h *headerSTAR) Prefix() []byte { return h[345:][:131] } +func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] } +func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] } +func (h *headerSTAR) Trailer() []byte { return h[508:][:4] } + +type headerUSTAR [blockSize]byte + +func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) } +func (h *headerUSTAR) Magic() []byte { return h[257:][:6] } +func (h *headerUSTAR) Version() []byte { return h[263:][:2] } +func (h *headerUSTAR) UserName() []byte { return h[265:][:32] } +func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] } +func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] } +func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] } +func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] } + +type sparseArray []byte + +func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) } +func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] } +func (s sparseArray) MaxEntries() int { return len(s) / 24 } + +type sparseNode []byte + +func (s sparseNode) Offset() []byte { return s[00:][:12] } +func (s sparseNode) NumBytes() []byte { return s[12:][:12] } diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go index e2a2a5440e04c2..096ef082bf8764 100644 --- a/src/archive/tar/reader.go +++ b/src/archive/tar/reader.go @@ -29,11 +29,11 @@ const maxNanoSecondIntSize = 9 // The Next method advances to the next file in the archive (including the first), // and then it can be treated as an io.Reader to access the file's data. type Reader struct { - r io.Reader - err error - pad int64 // amount of padding (ignored) after current file entry - curr numBytesReader // reader for current file entry - hdrBuff [blockSize]byte // buffer to use in readHeader + r io.Reader + err error + pad int64 // amount of padding (ignored) after current file entry + curr numBytesReader // reader for current file entry + blk block // buffer to use as temporary local storage } type parser struct { @@ -98,17 +98,6 @@ const ( paxGNUSparseRealSize = "GNU.sparse.realsize" ) -// Keywords for old GNU sparse headers -const ( - oldGNUSparseMainHeaderOffset = 386 - oldGNUSparseMainHeaderIsExtendedOffset = 482 - oldGNUSparseMainHeaderNumEntries = 4 - oldGNUSparseExtendedHeaderIsExtendedOffset = 504 - oldGNUSparseExtendedHeaderNumEntries = 21 - oldGNUSparseOffsetSize = 12 - oldGNUSparseNumBytesSize = 12 -) - // NewReader creates a new Reader reading from r. func NewReader(r io.Reader) *Reader { return &Reader{r: r} } @@ -542,17 +531,6 @@ func (tr *Reader) skipUnread() error { return tr.err } -func (tr *Reader) verifyChecksum(header []byte) bool { - if tr.err != nil { - return false - } - - var p parser - given := p.parseOctal(header[148:156]) - unsigned, signed := checksum(header) - return p.err == nil && (given == unsigned || given == signed) -} - // readHeader reads the next block header and assumes that the underlying reader // is already aligned to a block boundary. // @@ -561,19 +539,16 @@ func (tr *Reader) verifyChecksum(header []byte) bool { // * Exactly 1 block of zeros is read and EOF is hit. // * At least 2 blocks of zeros are read. func (tr *Reader) readHeader() *Header { - header := tr.hdrBuff[:] - copy(header, zeroBlock) - - if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { + if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil { return nil // io.EOF is okay here } // Two blocks of zero bytes marks the end of the archive. - if bytes.Equal(header, zeroBlock[0:blockSize]) { - if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { + if bytes.Equal(tr.blk[:], zeroBlock[:]) { + if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil { return nil // io.EOF is okay here } - if bytes.Equal(header, zeroBlock[0:blockSize]) { + if bytes.Equal(tr.blk[:], zeroBlock[:]) { tr.err = io.EOF } else { tr.err = ErrHeader // zero block and then non-zero block @@ -581,71 +556,55 @@ func (tr *Reader) readHeader() *Header { return nil } - if !tr.verifyChecksum(header) { + // Verify the header matches a known format. + format := tr.blk.GetFormat() + if format == formatUnknown { tr.err = ErrHeader return nil } - // Unpack var p parser hdr := new(Header) - s := slicer(header) - - hdr.Name = p.parseString(s.next(100)) - hdr.Mode = p.parseNumeric(s.next(8)) - hdr.Uid = int(p.parseNumeric(s.next(8))) - hdr.Gid = int(p.parseNumeric(s.next(8))) - hdr.Size = p.parseNumeric(s.next(12)) - hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0) - s.next(8) // chksum - hdr.Typeflag = s.next(1)[0] - hdr.Linkname = p.parseString(s.next(100)) - - // The remainder of the header depends on the value of magic. - // The original (v7) version of tar had no explicit magic field, - // so its magic bytes, like the rest of the block, are NULs. - magic := string(s.next(8)) // contains version field as well. - var format string - switch { - case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988) - if string(header[508:512]) == "tar\x00" { - format = "star" - } else { - format = "posix" - } - case magic == "ustar \x00": // old GNU tar - format = "gnu" - } - switch format { - case "posix", "gnu", "star": - hdr.Uname = p.parseString(s.next(32)) - hdr.Gname = p.parseString(s.next(32)) - devmajor := s.next(8) - devminor := s.next(8) + // Unpack the V7 header. + v7 := tr.blk.V7() + hdr.Name = p.parseString(v7.Name()) + hdr.Mode = p.parseNumeric(v7.Mode()) + hdr.Uid = int(p.parseNumeric(v7.UID())) + hdr.Gid = int(p.parseNumeric(v7.GID())) + hdr.Size = p.parseNumeric(v7.Size()) + hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0) + hdr.Typeflag = v7.TypeFlag()[0] + hdr.Linkname = p.parseString(v7.LinkName()) + + // Unpack format specific fields. + if format > formatV7 { + ustar := tr.blk.USTAR() + hdr.Uname = p.parseString(ustar.UserName()) + hdr.Gname = p.parseString(ustar.GroupName()) if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock { - hdr.Devmajor = p.parseNumeric(devmajor) - hdr.Devminor = p.parseNumeric(devminor) + hdr.Devmajor = p.parseNumeric(ustar.DevMajor()) + hdr.Devminor = p.parseNumeric(ustar.DevMinor()) } + var prefix string switch format { - case "posix", "gnu": - prefix = p.parseString(s.next(155)) - case "star": - prefix = p.parseString(s.next(131)) - hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0) - hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0) + case formatUSTAR, formatGNU: + // TODO(dsnet): Do not use the prefix field for the GNU format! + // See golang.org/issues/12594 + ustar := tr.blk.USTAR() + prefix = p.parseString(ustar.Prefix()) + case formatSTAR: + star := tr.blk.STAR() + prefix = p.parseString(star.Prefix()) + hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0) + hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0) } if len(prefix) > 0 { hdr.Name = prefix + "/" + hdr.Name } } - if p.err != nil { - tr.err = p.err - return nil - } - nb := hdr.Size if isHeaderOnlyType(hdr.Typeflag) { nb = 0 @@ -662,14 +621,14 @@ func (tr *Reader) readHeader() *Header { // Check for old GNU sparse format entry. if hdr.Typeflag == TypeGNUSparse { // Get the real size of the file. - hdr.Size = p.parseNumeric(header[483:495]) + hdr.Size = p.parseNumeric(tr.blk.GNU().RealSize()) if p.err != nil { tr.err = p.err return nil } // Read the sparse map. - sp := tr.readOldGNUSparseMap(header) + sp := tr.readOldGNUSparseMap(&tr.blk) if tr.err != nil { return nil } @@ -681,26 +640,24 @@ func (tr *Reader) readHeader() *Header { } } + if p.err != nil { + tr.err = p.err + return nil + } + return hdr } // readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format. // The sparse map is stored in the tar header if it's small enough. If it's larger than four entries, // then one or more extension headers are used to store the rest of the sparse map. -func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { +func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry { var p parser - isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0 - spCap := oldGNUSparseMainHeaderNumEntries - if isExtended { - spCap += oldGNUSparseExtendedHeaderNumEntries - } - sp := make([]sparseEntry, 0, spCap) - s := slicer(header[oldGNUSparseMainHeaderOffset:]) - - // Read the four entries from the main tar header - for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ { - offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize)) - numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize)) + var s sparseArray = blk.GNU().Sparse() + var sp = make([]sparseEntry, 0, s.MaxEntries()) + for i := 0; i < s.MaxEntries(); i++ { + offset := p.parseOctal(s.Entry(i).Offset()) + numBytes := p.parseOctal(s.Entry(i).NumBytes()) if p.err != nil { tr.err = p.err return nil @@ -711,17 +668,17 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) } - for isExtended { + for s.IsExtended()[0] > 0 { // There are more entries. Read an extension header and parse its entries. - sparseHeader := make([]byte, blockSize) - if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil { + var blk block + if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil { return nil } - isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0 - s = slicer(sparseHeader) - for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ { - offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize)) - numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize)) + s = blk.Sparse() + + for i := 0; i < s.MaxEntries(); i++ { + offset := p.parseOctal(s.Entry(i).Offset()) + numBytes := p.parseOctal(s.Entry(i).NumBytes()) if p.err != nil { tr.err = p.err return nil diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go index 944b2d49529adf..426e4434eb7544 100644 --- a/src/archive/tar/writer.go +++ b/src/archive/tar/writer.go @@ -36,10 +36,10 @@ type Writer struct { nb int64 // number of unwritten bytes for current file entry pad int64 // amount of padding to write after current file entry closed bool - usedBinary bool // whether the binary numeric field extension was used - preferPax bool // use pax header instead of binary numeric header - hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header - paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header + usedBinary bool // whether the binary numeric field extension was used + preferPax bool // use PAX header instead of binary numeric header + hdrBuff block // buffer to use in writeHeader when writing a regular header + paxHdrBuff block // buffer to use in writeHeader when writing a PAX header } type formatter struct { @@ -153,27 +153,24 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { // a map to hold pax header records, if any are needed paxHeaders := make(map[string]string) - // TODO(shanemhansen): we might want to use PAX headers for + // TODO(dsnet): we might want to use PAX headers for // subsecond time resolution, but for now let's just capture // too long fields or non ascii characters - var f formatter - var header []byte - // We need to select which scratch buffer to use carefully, // since this method is called recursively to write PAX headers. // If allowPax is true, this is the non-recursive call, and we will use hdrBuff. // If allowPax is false, we are being called by writePAXHeader, and hdrBuff is // already being used by the non-recursive call, so we must use paxHdrBuff. - header = tw.hdrBuff[:] + header := &tw.hdrBuff if !allowPax { - header = tw.paxHdrBuff[:] + header = &tw.paxHdrBuff } - copy(header, zeroBlock) - s := slicer(header) + copy(header[:], zeroBlock[:]) // Wrappers around formatter that automatically sets paxHeaders if the // argument extends beyond the capacity of the input byte slice. + var f formatter var formatString = func(b []byte, s string, paxKeyword string) { needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s) if needsPaxHeader { @@ -202,44 +199,33 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { f.formatNumeric(b, x) } - // keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax - pathHeaderBytes := s.next(fileNameSize) - - formatString(pathHeaderBytes, hdr.Name, paxPath) - // Handle out of range ModTime carefully. var modTime int64 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { modTime = hdr.ModTime.Unix() } - f.formatOctal(s.next(8), hdr.Mode) // 100:108 - formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116 - formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124 - formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136 - formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity - s.next(8) // chksum (148:156) - s.next(1)[0] = hdr.Typeflag // 156:157 - - formatString(s.next(100), hdr.Linkname, paxLinkpath) - - copy(s.next(8), []byte("ustar\x0000")) // 257:265 - formatString(s.next(32), hdr.Uname, paxUname) // 265:297 - formatString(s.next(32), hdr.Gname, paxGname) // 297:329 - formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337 - formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345 - - // keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax - prefixHeaderBytes := s.next(155) - formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix + v7 := header.V7() + formatString(v7.Name(), hdr.Name, paxPath) + // TODO(dsnet): The GNU format permits the mode field to be encoded in + // base-256 format. Thus, we can use formatNumeric instead of formatOctal. + f.formatOctal(v7.Mode(), hdr.Mode) + formatNumeric(v7.UID(), int64(hdr.Uid), paxUid) + formatNumeric(v7.GID(), int64(hdr.Gid), paxGid) + formatNumeric(v7.Size(), hdr.Size, paxSize) + // TODO(dsnet): Consider using PAX for finer time granularity. + formatNumeric(v7.ModTime(), modTime, paxNone) + v7.TypeFlag()[0] = hdr.Typeflag + formatString(v7.LinkName(), hdr.Linkname, paxLinkpath) + + ustar := header.USTAR() + formatString(ustar.UserName(), hdr.Uname, paxUname) + formatString(ustar.GroupName(), hdr.Gname, paxGname) + formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone) + formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone) - // Use the GNU magic instead of POSIX magic if we used any GNU extensions. - if tw.usedBinary { - copy(header[257:265], []byte("ustar \x00")) - } - - _, paxPathUsed := paxHeaders[paxPath] // try to use a ustar header when only the name is too long + _, paxPathUsed := paxHeaders[paxPath] if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed { prefix, suffix, ok := splitUSTARPath(hdr.Name) if ok { @@ -247,16 +233,16 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { delete(paxHeaders, paxPath) // Update the path fields - formatString(pathHeaderBytes, suffix, paxNone) - formatString(prefixHeaderBytes, prefix, paxNone) + formatString(v7.Name(), suffix, paxNone) + formatString(ustar.Prefix(), prefix, paxNone) } } - // The chksum field is terminated by a NUL and a space. - // This is different from the other octal fields. - chksum, _ := checksum(header) - f.formatOctal(header[148:155], chksum) // Never fails - header[155] = ' ' + if tw.usedBinary { + header.SetFormat(formatGNU) + } else { + header.SetFormat(formatUSTAR) + } // Check if there were any formatting errors. if f.err != nil { @@ -281,7 +267,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { tw.nb = hdr.Size tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize - _, tw.err = tw.w.Write(header) + _, tw.err = tw.w.Write(header[:]) return tw.err } @@ -289,10 +275,10 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { // If the path is not splittable, then it will return ("", "", false). func splitUSTARPath(name string) (prefix, suffix string, ok bool) { length := len(name) - if length <= fileNameSize || !isASCII(name) { + if length <= nameSize || !isASCII(name) { return "", "", false - } else if length > fileNamePrefixSize+1 { - length = fileNamePrefixSize + 1 + } else if length > prefixSize+1 { + length = prefixSize + 1 } else if name[length-1] == '/' { length-- } @@ -300,7 +286,7 @@ func splitUSTARPath(name string) (prefix, suffix string, ok bool) { i := strings.LastIndex(name[:length], "/") nlen := len(name) - i - 1 // nlen is length of suffix plen := i // plen is length of prefix - if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize { + if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize { return "", "", false } return name[:i], name[i+1:], true @@ -323,8 +309,8 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro fullName := path.Join(dir, "PaxHeaders.0", file) ascii := toASCII(fullName) - if len(ascii) > 100 { - ascii = ascii[:100] + if len(ascii) > nameSize { + ascii = ascii[:nameSize] } ext.Name = ascii // Construct the body @@ -407,7 +393,7 @@ func (tw *Writer) Close() error { // trailer: two zero blocks for i := 0; i < 2; i++ { - _, tw.err = tw.w.Write(zeroBlock) + _, tw.err = tw.w.Write(zeroBlock[:]) if tw.err != nil { break } diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go index 6e91d907ce96bd..27aa8e5dab6724 100644 --- a/src/archive/tar/writer_test.go +++ b/src/archive/tar/writer_test.go @@ -587,17 +587,17 @@ func TestSplitUSTARPath(t *testing.T) { {"", "", "", false}, {"abc", "", "", false}, {"用戶名", "", "", false}, - {sr("a", fileNameSize), "", "", false}, - {sr("a", fileNameSize) + "/", "", "", false}, - {sr("a", fileNameSize) + "/a", sr("a", fileNameSize), "a", true}, - {sr("a", fileNamePrefixSize) + "/", "", "", false}, - {sr("a", fileNamePrefixSize) + "/a", sr("a", fileNamePrefixSize), "a", true}, - {sr("a", fileNameSize+1), "", "", false}, - {sr("/", fileNameSize+1), sr("/", fileNameSize-1), "/", true}, - {sr("a", fileNamePrefixSize) + "/" + sr("b", fileNameSize), - sr("a", fileNamePrefixSize), sr("b", fileNameSize), true}, - {sr("a", fileNamePrefixSize) + "//" + sr("b", fileNameSize), "", "", false}, - {sr("a/", fileNameSize), sr("a/", 77) + "a", sr("a/", 22), true}, + {sr("a", nameSize), "", "", false}, + {sr("a", nameSize) + "/", "", "", false}, + {sr("a", nameSize) + "/a", sr("a", nameSize), "a", true}, + {sr("a", prefixSize) + "/", "", "", false}, + {sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true}, + {sr("a", nameSize+1), "", "", false}, + {sr("/", nameSize+1), sr("/", nameSize-1), "/", true}, + {sr("a", prefixSize) + "/" + sr("b", nameSize), + sr("a", prefixSize), sr("b", nameSize), true}, + {sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false}, + {sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true}, } for _, v := range vectors { From b90cb3f4716d3fede57bf8e798d27406fba5c294 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 5 May 2016 17:52:37 -0700 Subject: [PATCH 009/267] cmd/go: fail with nice error message on bad GOOS/GOARCH pair Fixes #12272 Change-Id: I2115ec62ed4061084c482eb385a583a1c1909888 Reviewed-on: https://go-review.googlesource.com/22838 Reviewed-by: Ian Lance Taylor Reviewed-by: Minux Ma --- .gitignore | 1 + src/cmd/dist/build.go | 2 ++ src/cmd/dist/buildgo.go | 15 +++++++++++---- src/cmd/go/build.go | 6 ++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 6851e147d33877..7173067a759c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ misc/cgo/stdio/run.out misc/cgo/testso/main src/cmd/cgo/zdefaultcc.go src/cmd/go/zdefaultcc.go +src/cmd/go/zosarch.go src/cmd/internal/obj/zbootstrap.go src/go/build/zcgo.go src/go/doc/headscan diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 04a13b2365ce6a..aa12aa9dc3da8c 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -464,6 +464,7 @@ var deptab = []struct { }{ {"cmd/go", []string{ "zdefaultcc.go", + "zosarch.go", }}, {"runtime/internal/sys", []string{ "zversion.go", @@ -485,6 +486,7 @@ var gentab = []struct { gen func(string, string) }{ {"zdefaultcc.go", mkzdefaultcc}, + {"zosarch.go", mkzosarch}, {"zversion.go", mkzversion}, {"zcgo.go", mkzcgo}, diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go index 2b68fc222460c8..c367c70b043089 100644 --- a/src/cmd/dist/buildgo.go +++ b/src/cmd/dist/buildgo.go @@ -23,9 +23,7 @@ import ( // It is invoked to write cmd/go/zdefaultcc.go // but we also write cmd/cgo/zdefaultcc.go func mkzdefaultcc(dir, file string) { - var out string - - out = fmt.Sprintf( + out := fmt.Sprintf( "// auto generated by go tool dist\n"+ "\n"+ "package main\n"+ @@ -42,7 +40,16 @@ func mkzdefaultcc(dir, file string) { writefile(out, file, writeSkipSame) } -// mkzcgo writes zcgo.go for go/build package: +// mkzcgo writes zosarch.go for cmd/go. +func mkzosarch(dir, file string) { + var buf bytes.Buffer + buf.WriteString("// auto generated by go tool dist\n\n") + buf.WriteString("package main\n\n") + fmt.Fprintf(&buf, "var osArchSupportsCgo = %#v", cgoEnabled) + writefile(buf.String(), file, writeSkipSame) +} + +// mkzcgo writes zcgo.go for the go/build package: // // package build // var cgoEnabled = map[string]bool{} diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 0102b5e08a2272..09e2122b0cc1db 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -669,6 +669,12 @@ var ( func init() { goarch = buildContext.GOARCH goos = buildContext.GOOS + + if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok { + fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch) + os.Exit(2) + } + if goos == "windows" { exeSuffix = ".exe" } From d68f800620b4295039912066970fb2be914f1d1e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 May 2016 17:46:58 -0700 Subject: [PATCH 010/267] test: update test for issue 15548 Accidentally checked in the version of file c.go that doesn't exhibit the bug - hence the test was not testing the bug fix. Double-checked that this version exposes the bug w/o the fix. Change-Id: Ie4dc455229d1ac802a80164b5d549c2ad4d971f5 Reviewed-on: https://go-review.googlesource.com/22837 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Minux Ma --- test/fixedbugs/issue15548.dir/c.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixedbugs/issue15548.dir/c.go b/test/fixedbugs/issue15548.dir/c.go index ce6e3204b3ea2c..6d3f3be53ec2a4 100644 --- a/test/fixedbugs/issue15548.dir/c.go +++ b/test/fixedbugs/issue15548.dir/c.go @@ -5,6 +5,6 @@ package c import ( - _ "./a" _ "./b" + _ "./a" ) From ef92857e27556804d66e72e2360dc2c6b6554bd7 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 5 May 2016 09:10:49 -0700 Subject: [PATCH 011/267] cmd/go, cmd/cgo: pass "-mabi=64" to gcc on mips64 Change-Id: I9ac2ae57a00cee23d6255db02419b0a0f087d4f3 Reviewed-on: https://go-review.googlesource.com/22801 Reviewed-by: Minux Ma Run-TryBot: Minux Ma --- src/cmd/cgo/gcc.go | 2 ++ src/cmd/go/build.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 3ee4461352c30d..97ef824c9342a7 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1089,6 +1089,8 @@ func (p *Package) gccMachine() []string { return []string{"-m31"} case "s390x": return []string{"-m64"} + case "mips64", "mips64le": + return []string{"-mabi=64"} } return nil } diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 09e2122b0cc1db..6bef09b66b86bf 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -3103,6 +3103,8 @@ func (b *builder) gccArchArgs() []string { return []string{"-marm"} // not thumb case "s390x": return []string{"-m64", "-march=z196"} + case "mips64", "mips64le": + return []string{"-mabi=64"} } return nil } From 2e32efc44ac86cce3bd0808e6049d8c9b0225ba8 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 6 May 2016 00:53:42 -0400 Subject: [PATCH 012/267] runtime: get randomness from AT_RANDOM AUXV on linux/mips64x Fixes #15148. Change-Id: If3b628f30521adeec1625689dbc98aaf4a9ec858 Reviewed-on: https://go-review.googlesource.com/22811 Reviewed-by: Keith Randall Run-TryBot: Minux Ma Reviewed-by: Cherry Zhang TryBot-Result: Gobot Gobot --- src/runtime/os_linux_mips64x.go | 11 +++++++++++ src/runtime/os_linux_noauxv.go | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go index 92b5c82af7c20f..8039b2fac9b7a3 100644 --- a/src/runtime/os_linux_mips64x.go +++ b/src/runtime/os_linux_mips64x.go @@ -9,6 +9,17 @@ package runtime var randomNumber uint32 +func archauxv(tag, val uintptr) { + switch tag { + case _AT_RANDOM: + // sysargs filled in startupRandomData, but that + // pointer may not be word aligned, so we must treat + // it as a byte array. + randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 | + uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24 + } +} + //go:nosplit func cputicks() int64 { // Currently cputicks() is used in blocking profiler and to seed fastrand1(). diff --git a/src/runtime/os_linux_noauxv.go b/src/runtime/os_linux_noauxv.go index 0b46f594ce0117..22522dd803dc02 100644 --- a/src/runtime/os_linux_noauxv.go +++ b/src/runtime/os_linux_noauxv.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!arm,!arm64 +// +build !amd64,!arm,!arm64,!mips64,!mips64le package runtime From 009c002c925e391e5a7a406c9175aefafb6c9e3c Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Fri, 29 Apr 2016 16:14:57 +0300 Subject: [PATCH 013/267] cmd/internal/obj/x86: add AVX2 instrutions needed for sha1/sha512/sha256 acceleration This means: VPSHUFB, VPSHUFD, VPERM2F128, VPALIGNR, VPADDQ, VPADDD, VPSRLDQ, VPSLLDQ, VPSRLQ, VPSLLQ, VPSRLD, VPSLLD, VPOR, VPBLENDD, VINSERTI128, VPERM2I128, RORXL, RORXQ. Change-Id: Ief27190ee6acfa86b109262af5d999bc101e923d Reviewed-on: https://go-review.googlesource.com/22606 Run-TryBot: Ilya Tocar TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/cmd/asm/internal/arch/amd64.go | 28 ++ src/cmd/asm/internal/asm/asm.go | 28 +- src/cmd/asm/internal/asm/testdata/amd64enc.s | 368 +++++++++---------- src/cmd/internal/obj/util.go | 9 +- src/cmd/internal/obj/x86/a.out.go | 18 + src/cmd/internal/obj/x86/anames.go | 18 + src/cmd/internal/obj/x86/asm6.go | 84 ++++- 7 files changed, 364 insertions(+), 189 deletions(-) create mode 100644 src/cmd/asm/internal/arch/amd64.go diff --git a/src/cmd/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go new file mode 100644 index 00000000000000..625e136d1db6a2 --- /dev/null +++ b/src/cmd/asm/internal/arch/amd64.go @@ -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. + +// This file encapsulates some of the odd characteristics of the +// AMD64 instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" +) + +// IsAMD4OP reports whether the op (as defined by an ppc64.A* constant) is +// The FMADD-like instructions behave similarly. +func IsAMD4OP(op obj.As) bool { + switch op { + case x86.AVPERM2F128, + x86.AVPALIGNR, + x86.AVPERM2I128, + x86.AVINSERTI128, + x86.AVPBLENDD: + return true + } + return false +} diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 24906e2cce200c..c9c64203ae68bd 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -568,6 +568,15 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] + case sys.AMD64: + // Catch missing operand here, because we store immediate as part of From3, and can't distinguish + // missing operand from legal value 0 in obj/x86/asm6. + if arch.IsAMD4OP(op) { + p.errorf("4 operands required, but only 3 are provided for %s instruction", obj.Aconv(op)) + } + prog.From = a[0] + prog.From3 = newAddr(a[1]) + prog.To = a[2] case sys.ARM64: // ARM64 instructions with one input and two outputs. if arch.IsARM64STLXR(op) { @@ -583,7 +592,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] - case sys.AMD64, sys.I386: + case sys.I386: prog.From = a[0] prog.From3 = newAddr(a[1]) prog.To = a[2] @@ -640,6 +649,23 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.Reg = r1 break } + if p.arch.Family == sys.AMD64 { + // 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8 + // So From3 is always just a register, so we store imm8 in Offset field, + // to avoid increasing size of Prog. + prog.From = a[1] + prog.From3 = newAddr(a[2]) + if a[0].Type != obj.TYPE_CONST { + p.errorf("first operand must be an immediate in %s instruction", obj.Aconv(op)) + } + if prog.From3.Type != obj.TYPE_REG { + p.errorf("third operand must be a register in %s instruction", obj.Aconv(op)) + } + prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0])) + prog.To = a[3] + prog.RegTo2 = -1 + break + } if p.arch.Family == sys.ARM64 { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc.s b/src/cmd/asm/internal/asm/testdata/amd64enc.s index 63fdcac27db840..22dfe127b3db0b 100644 --- a/src/cmd/asm/internal/asm/testdata/amd64enc.s +++ b/src/cmd/asm/internal/asm/testdata/amd64enc.s @@ -5008,22 +5008,22 @@ TEXT asmtest(SB),7,$0 RORB $7, (R11) // 41c00b07 RORB $7, DL // c0ca07 RORB $7, R11 // 41c0cb07 - //TODO: RORXL $7, (BX), DX // c4e37bf01307 - //TODO: RORXL $7, (R11), DX // c4c37bf01307 - //TODO: RORXL $7, DX, DX // c4e37bf0d207 - //TODO: RORXL $7, R11, DX // c4c37bf0d307 - //TODO: RORXL $7, (BX), R11 // c4637bf01b07 - //TODO: RORXL $7, (R11), R11 // c4437bf01b07 - //TODO: RORXL $7, DX, R11 // c4637bf0da07 - //TODO: RORXL $7, R11, R11 // c4437bf0db07 - //TODO: RORXQ $7, (BX), DX // c4e3fbf01307 - //TODO: RORXQ $7, (R11), DX // c4c3fbf01307 - //TODO: RORXQ $7, DX, DX // c4e3fbf0d207 - //TODO: RORXQ $7, R11, DX // c4c3fbf0d307 - //TODO: RORXQ $7, (BX), R11 // c463fbf01b07 - //TODO: RORXQ $7, (R11), R11 // c443fbf01b07 - //TODO: RORXQ $7, DX, R11 // c463fbf0da07 - //TODO: RORXQ $7, R11, R11 // c443fbf0db07 + RORXL $7, (BX), DX // c4e37bf01307 + RORXL $7, (R11), DX // c4c37bf01307 + RORXL $7, DX, DX // c4e37bf0d207 + RORXL $7, R11, DX // c4c37bf0d307 + RORXL $7, (BX), R11 // c4637bf01b07 + RORXL $7, (R11), R11 // c4437bf01b07 + RORXL $7, DX, R11 // c4637bf0da07 + RORXL $7, R11, R11 // c4437bf0db07 + RORXQ $7, (BX), DX // c4e3fbf01307 + RORXQ $7, (R11), DX // c4c3fbf01307 + RORXQ $7, DX, DX // c4e3fbf0d207 + RORXQ $7, R11, DX // c4c3fbf0d307 + RORXQ $7, (BX), R11 // c463fbf01b07 + RORXQ $7, (R11), R11 // c443fbf01b07 + RORXQ $7, DX, R11 // c463fbf0da07 + RORXQ $7, R11, R11 // c443fbf0db07 ROUNDPD $7, (BX), X2 // 660f3a091307 ROUNDPD $7, (R11), X2 // 66410f3a091307 ROUNDPD $7, X2, X2 // 660f3a09d207 @@ -7420,14 +7420,14 @@ TEXT asmtest(SB),7,$0 //TODO: VINSERTF128 $7, (R11), Y15, Y11 // c44305181b07 //TODO: VINSERTF128 $7, X2, Y15, Y11 // c4630518da07 //TODO: VINSERTF128 $7, X11, Y15, Y11 // c4430518db07 - //TODO: VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307 - //TODO: VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307 - //TODO: VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207 - //TODO: VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307 - //TODO: VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07 - //TODO: VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07 - //TODO: VINSERTI128 $7, X2, Y15, Y11 // c4630538da07 - //TODO: VINSERTI128 $7, X11, Y15, Y11 // c4430538db07 + VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307 + VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307 + VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207 + VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307 + VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07 + VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07 + VINSERTI128 $7, X2, Y15, Y11 // c4630538da07 + VINSERTI128 $7, X11, Y15, Y11 // c4430538db07 //TODO: VINSERTPS $7, (BX), X9, X2 // c4e331211307 //TODO: VINSERTPS $7, (R11), X9, X2 // c4c331211307 //TODO: VINSERTPS $7, X2, X9, X2 // c4e33121d207 @@ -8142,38 +8142,38 @@ TEXT asmtest(SB),7,$0 //TODO: VPADDB (R11), Y15, Y11 // c44105fc1b //TODO: VPADDB Y2, Y15, Y11 // c46105fcda or c505fcda //TODO: VPADDB Y11, Y15, Y11 // c44105fcdb - //TODO: VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13 - //TODO: VPADDD (R11), X9, X2 // c4c131fe13 - //TODO: VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2 - //TODO: VPADDD X11, X9, X2 // c4c131fed3 - //TODO: VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b - //TODO: VPADDD (R11), X9, X11 // c44131fe1b - //TODO: VPADDD X2, X9, X11 // c46131feda or c531feda - //TODO: VPADDD X11, X9, X11 // c44131fedb - //TODO: VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13 - //TODO: VPADDD (R11), Y15, Y2 // c4c105fe13 - //TODO: VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2 - //TODO: VPADDD Y11, Y15, Y2 // c4c105fed3 - //TODO: VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b - //TODO: VPADDD (R11), Y15, Y11 // c44105fe1b - //TODO: VPADDD Y2, Y15, Y11 // c46105feda or c505feda - //TODO: VPADDD Y11, Y15, Y11 // c44105fedb - //TODO: VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413 - //TODO: VPADDQ (R11), X9, X2 // c4c131d413 - //TODO: VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2 - //TODO: VPADDQ X11, X9, X2 // c4c131d4d3 - //TODO: VPADDQ (BX), X9, X11 // c46131d41b or c531d41b - //TODO: VPADDQ (R11), X9, X11 // c44131d41b - //TODO: VPADDQ X2, X9, X11 // c46131d4da or c531d4da - //TODO: VPADDQ X11, X9, X11 // c44131d4db - //TODO: VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413 - //TODO: VPADDQ (R11), Y15, Y2 // c4c105d413 - //TODO: VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2 - //TODO: VPADDQ Y11, Y15, Y2 // c4c105d4d3 - //TODO: VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b - //TODO: VPADDQ (R11), Y15, Y11 // c44105d41b - //TODO: VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da - //TODO: VPADDQ Y11, Y15, Y11 // c44105d4db + VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13 + VPADDD (R11), X9, X2 // c4c131fe13 + VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2 + VPADDD X11, X9, X2 // c4c131fed3 + VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b + VPADDD (R11), X9, X11 // c44131fe1b + VPADDD X2, X9, X11 // c46131feda or c531feda + VPADDD X11, X9, X11 // c44131fedb + VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13 + VPADDD (R11), Y15, Y2 // c4c105fe13 + VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2 + VPADDD Y11, Y15, Y2 // c4c105fed3 + VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b + VPADDD (R11), Y15, Y11 // c44105fe1b + VPADDD Y2, Y15, Y11 // c46105feda or c505feda + VPADDD Y11, Y15, Y11 // c44105fedb + VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413 + VPADDQ (R11), X9, X2 // c4c131d413 + VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2 + VPADDQ X11, X9, X2 // c4c131d4d3 + VPADDQ (BX), X9, X11 // c46131d41b or c531d41b + VPADDQ (R11), X9, X11 // c44131d41b + VPADDQ X2, X9, X11 // c46131d4da or c531d4da + VPADDQ X11, X9, X11 // c44131d4db + VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413 + VPADDQ (R11), Y15, Y2 // c4c105d413 + VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2 + VPADDQ Y11, Y15, Y2 // c4c105d4d3 + VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b + VPADDQ (R11), Y15, Y11 // c44105d41b + VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da + VPADDQ Y11, Y15, Y11 // c44105d4db //TODO: VPADDSB (BX), X9, X2 // c4e131ec13 or c5b1ec13 //TODO: VPADDSB (R11), X9, X2 // c4c131ec13 //TODO: VPADDSB X2, X9, X2 // c4e131ecd2 or c5b1ecd2 @@ -8262,14 +8262,14 @@ TEXT asmtest(SB),7,$0 //TODO: VPALIGNR $7, (R11), X9, X11 // c443310f1b07 //TODO: VPALIGNR $7, X2, X9, X11 // c463310fda07 //TODO: VPALIGNR $7, X11, X9, X11 // c443310fdb07 - //TODO: VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307 - //TODO: VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307 - //TODO: VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207 - //TODO: VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307 - //TODO: VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07 - //TODO: VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07 - //TODO: VPALIGNR $7, Y2, Y15, Y11 // c463050fda07 - //TODO: VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07 + VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307 + VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307 + VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207 + VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307 + VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07 + VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07 + VPALIGNR $7, Y2, Y15, Y11 // c463050fda07 + VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07 VPAND (BX), X9, X2 // c4e131db13 or c5b1db13 VPAND (R11), X9, X2 // c4c131db13 VPAND X2, X9, X2 // c4e131dbd2 or c5b1dbd2 @@ -8342,14 +8342,14 @@ TEXT asmtest(SB),7,$0 //TODO: VPBLENDD $7, (R11), X9, X11 // c44331021b07 //TODO: VPBLENDD $7, X2, X9, X11 // c4633102da07 //TODO: VPBLENDD $7, X11, X9, X11 // c4433102db07 - //TODO: VPBLENDD $7, (BX), Y15, Y2 // c4e305021307 - //TODO: VPBLENDD $7, (R11), Y15, Y2 // c4c305021307 - //TODO: VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207 - //TODO: VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307 - //TODO: VPBLENDD $7, (BX), Y15, Y11 // c46305021b07 - //TODO: VPBLENDD $7, (R11), Y15, Y11 // c44305021b07 - //TODO: VPBLENDD $7, Y2, Y15, Y11 // c4630502da07 - //TODO: VPBLENDD $7, Y11, Y15, Y11 // c4430502db07 + VPBLENDD $7, (BX), Y15, Y2 // c4e305021307 + VPBLENDD $7, (R11), Y15, Y2 // c4c305021307 + VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207 + VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307 + VPBLENDD $7, (BX), Y15, Y11 // c46305021b07 + VPBLENDD $7, (R11), Y15, Y11 // c44305021b07 + VPBLENDD $7, Y2, Y15, Y11 // c4630502da07 + VPBLENDD $7, Y11, Y15, Y11 // c4430502db07 //TODO: VPBLENDVB XMM12, (BX), X9, X2 // c4e3314c13c0 //TODO: VPBLENDVB XMM12, (R11), X9, X2 // c4c3314c13c0 //TODO: VPBLENDVB XMM12, X2, X9, X2 // c4e3314cd2c0 @@ -8614,22 +8614,22 @@ TEXT asmtest(SB),7,$0 //TODO: VPCMPISTRM $7, (R11), X11 // c44379621b07 //TODO: VPCMPISTRM $7, X2, X11 // c4637962da07 //TODO: VPCMPISTRM $7, X11, X11 // c4437962db07 - //TODO: VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307 - //TODO: VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307 - //TODO: VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207 - //TODO: VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307 - //TODO: VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07 - //TODO: VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07 - //TODO: VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07 - //TODO: VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07 - //TODO: VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307 - //TODO: VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307 - //TODO: VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207 - //TODO: VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307 - //TODO: VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07 - //TODO: VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07 - //TODO: VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07 - //TODO: VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07 + VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307 + VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307 + VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207 + VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307 + VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07 + VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07 + VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07 + VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07 + VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307 + VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307 + VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207 + VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307 + VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07 + VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07 + VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07 + VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07 //TODO: VPERMD (BX), Y15, Y2 // c4e2053613 //TODO: VPERMD (R11), Y15, Y2 // c4c2053613 //TODO: VPERMD Y2, Y15, Y2 // c4e20536d2 @@ -9462,22 +9462,22 @@ TEXT asmtest(SB),7,$0 //TODO: VPMULUDQ (R11), Y15, Y11 // c44105f41b //TODO: VPMULUDQ Y2, Y15, Y11 // c46105f4da or c505f4da //TODO: VPMULUDQ Y11, Y15, Y11 // c44105f4db - //TODO: VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13 - //TODO: VPOR (R11), X9, X2 // c4c131eb13 - //TODO: VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2 - //TODO: VPOR X11, X9, X2 // c4c131ebd3 - //TODO: VPOR (BX), X9, X11 // c46131eb1b or c531eb1b - //TODO: VPOR (R11), X9, X11 // c44131eb1b - //TODO: VPOR X2, X9, X11 // c46131ebda or c531ebda - //TODO: VPOR X11, X9, X11 // c44131ebdb - //TODO: VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13 - //TODO: VPOR (R11), Y15, Y2 // c4c105eb13 - //TODO: VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2 - //TODO: VPOR Y11, Y15, Y2 // c4c105ebd3 - //TODO: VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b - //TODO: VPOR (R11), Y15, Y11 // c44105eb1b - //TODO: VPOR Y2, Y15, Y11 // c46105ebda or c505ebda - //TODO: VPOR Y11, Y15, Y11 // c44105ebdb + VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13 + VPOR (R11), X9, X2 // c4c131eb13 + VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2 + VPOR X11, X9, X2 // c4c131ebd3 + VPOR (BX), X9, X11 // c46131eb1b or c531eb1b + VPOR (R11), X9, X11 // c44131eb1b + VPOR X2, X9, X11 // c46131ebda or c531ebda + VPOR X11, X9, X11 // c44131ebdb + VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13 + VPOR (R11), Y15, Y2 // c4c105eb13 + VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2 + VPOR Y11, Y15, Y2 // c4c105ebd3 + VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b + VPOR (R11), Y15, Y11 // c44105eb1b + VPOR Y2, Y15, Y11 // c46105ebda or c505ebda + VPOR Y11, Y15, Y11 // c44105ebdb //TODO: VPSADBW (BX), X9, X2 // c4e131f613 or c5b1f613 //TODO: VPSADBW (R11), X9, X2 // c4c131f613 //TODO: VPSADBW X2, X9, X2 // c4e131f6d2 or c5b1f6d2 @@ -9494,38 +9494,38 @@ TEXT asmtest(SB),7,$0 //TODO: VPSADBW (R11), Y15, Y11 // c44105f61b //TODO: VPSADBW Y2, Y15, Y11 // c46105f6da or c505f6da //TODO: VPSADBW Y11, Y15, Y11 // c44105f6db - //TODO: VPSHUFB (BX), X9, X2 // c4e2310013 - //TODO: VPSHUFB (R11), X9, X2 // c4c2310013 - //TODO: VPSHUFB X2, X9, X2 // c4e23100d2 - //TODO: VPSHUFB X11, X9, X2 // c4c23100d3 - //TODO: VPSHUFB (BX), X9, X11 // c46231001b - //TODO: VPSHUFB (R11), X9, X11 // c44231001b - //TODO: VPSHUFB X2, X9, X11 // c4623100da - //TODO: VPSHUFB X11, X9, X11 // c4423100db - //TODO: VPSHUFB (BX), Y15, Y2 // c4e2050013 - //TODO: VPSHUFB (R11), Y15, Y2 // c4c2050013 - //TODO: VPSHUFB Y2, Y15, Y2 // c4e20500d2 - //TODO: VPSHUFB Y11, Y15, Y2 // c4c20500d3 - //TODO: VPSHUFB (BX), Y15, Y11 // c46205001b - //TODO: VPSHUFB (R11), Y15, Y11 // c44205001b - //TODO: VPSHUFB Y2, Y15, Y11 // c4620500da - //TODO: VPSHUFB Y11, Y15, Y11 // c4420500db - //TODO: VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307 - //TODO: VPSHUFD $7, (R11), X2 // c4c179701307 - //TODO: VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207 - //TODO: VPSHUFD $7, X11, X2 // c4c17970d307 - //TODO: VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07 - //TODO: VPSHUFD $7, (R11), X11 // c44179701b07 - //TODO: VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07 - //TODO: VPSHUFD $7, X11, X11 // c4417970db07 - //TODO: VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307 - //TODO: VPSHUFD $7, (R11), Y2 // c4c17d701307 - //TODO: VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207 - //TODO: VPSHUFD $7, Y11, Y2 // c4c17d70d307 - //TODO: VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07 - //TODO: VPSHUFD $7, (R11), Y11 // c4417d701b07 - //TODO: VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07 - //TODO: VPSHUFD $7, Y11, Y11 // c4417d70db07 + VPSHUFB (BX), X9, X2 // c4e2310013 + VPSHUFB (R11), X9, X2 // c4c2310013 + VPSHUFB X2, X9, X2 // c4e23100d2 + VPSHUFB X11, X9, X2 // c4c23100d3 + VPSHUFB (BX), X9, X11 // c46231001b + VPSHUFB (R11), X9, X11 // c44231001b + VPSHUFB X2, X9, X11 // c4623100da + VPSHUFB X11, X9, X11 // c4423100db + VPSHUFB (BX), Y15, Y2 // c4e2050013 + VPSHUFB (R11), Y15, Y2 // c4c2050013 + VPSHUFB Y2, Y15, Y2 // c4e20500d2 + VPSHUFB Y11, Y15, Y2 // c4c20500d3 + VPSHUFB (BX), Y15, Y11 // c46205001b + VPSHUFB (R11), Y15, Y11 // c44205001b + VPSHUFB Y2, Y15, Y11 // c4620500da + VPSHUFB Y11, Y15, Y11 // c4420500db + VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307 + VPSHUFD $7, (R11), X2 // c4c179701307 + VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207 + VPSHUFD $7, X11, X2 // c4c17970d307 + VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07 + VPSHUFD $7, (R11), X11 // c44179701b07 + VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07 + VPSHUFD $7, X11, X11 // c4417970db07 + VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307 + VPSHUFD $7, (R11), Y2 // c4c17d701307 + VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207 + VPSHUFD $7, Y11, Y2 // c4c17d70d307 + VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07 + VPSHUFD $7, (R11), Y11 // c4417d701b07 + VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07 + VPSHUFD $7, Y11, Y11 // c4417d70db07 //TODO: VPSHUFHW $7, (BX), X2 // c4e17a701307 or c5fa701307 //TODO: VPSHUFHW $7, (R11), X2 // c4c17a701307 //TODO: VPSHUFHW $7, X2, X2 // c4e17a70d207 or c5fa70d207 @@ -9606,30 +9606,30 @@ TEXT asmtest(SB),7,$0 //TODO: VPSIGNW (R11), Y15, Y11 // c44205091b //TODO: VPSIGNW Y2, Y15, Y11 // c4620509da //TODO: VPSIGNW Y11, Y15, Y11 // c4420509db - //TODO: VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213 - //TODO: VPSLLD (R11), X9, X2 // c4c131f213 - //TODO: VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2 - //TODO: VPSLLD X11, X9, X2 // c4c131f2d3 - //TODO: VPSLLD (BX), X9, X11 // c46131f21b or c531f21b - //TODO: VPSLLD (R11), X9, X11 // c44131f21b - //TODO: VPSLLD X2, X9, X11 // c46131f2da or c531f2da - //TODO: VPSLLD X11, X9, X11 // c44131f2db - //TODO: VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207 - //TODO: VPSLLD $7, X11, X9 // c4c13172f307 - //TODO: VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07 - //TODO: VPSLLDQ $7, X11, X9 // c4c13173fb07 - //TODO: VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07 - //TODO: VPSLLDQ $7, Y11, Y15 // c4c10573fb07 - //TODO: VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313 - //TODO: VPSLLQ (R11), X9, X2 // c4c131f313 - //TODO: VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2 - //TODO: VPSLLQ X11, X9, X2 // c4c131f3d3 - //TODO: VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b - //TODO: VPSLLQ (R11), X9, X11 // c44131f31b - //TODO: VPSLLQ X2, X9, X11 // c46131f3da or c531f3da - //TODO: VPSLLQ X11, X9, X11 // c44131f3db - //TODO: VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207 - //TODO: VPSLLQ $7, X11, X9 // c4c13173f307 + VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213 + VPSLLD (R11), X9, X2 // c4c131f213 + VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2 + VPSLLD X11, X9, X2 // c4c131f2d3 + VPSLLD (BX), X9, X11 // c46131f21b or c531f21b + VPSLLD (R11), X9, X11 // c44131f21b + VPSLLD X2, X9, X11 // c46131f2da or c531f2da + VPSLLD X11, X9, X11 // c44131f2db + VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207 + VPSLLD $7, X11, X9 // c4c13172f307 + VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07 + VPSLLDQ $7, X11, X9 // c4c13173fb07 + VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07 + VPSLLDQ $7, Y11, Y15 // c4c10573fb07 + VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313 + VPSLLQ (R11), X9, X2 // c4c131f313 + VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2 + VPSLLQ X11, X9, X2 // c4c131f3d3 + VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b + VPSLLQ (R11), X9, X11 // c44131f31b + VPSLLQ X2, X9, X11 // c46131f3da or c531f3da + VPSLLQ X11, X9, X11 // c44131f3db + VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207 + VPSLLQ $7, X11, X9 // c4c13173f307 //TODO: VPSLLVD (BX), X9, X2 // c4e2314713 //TODO: VPSLLVD (R11), X9, X2 // c4c2314713 //TODO: VPSLLVD X2, X9, X2 // c4e23147d2 @@ -9738,30 +9738,30 @@ TEXT asmtest(SB),7,$0 //TODO: VPSRAW X11, Y15, Y11 // c44105e1db //TODO: VPSRAW $7, Y2, Y15 // c4e10571e207 or c58571e207 //TODO: VPSRAW $7, Y11, Y15 // c4c10571e307 - //TODO: VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213 - //TODO: VPSRLD (R11), X9, X2 // c4c131d213 - //TODO: VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2 - //TODO: VPSRLD X11, X9, X2 // c4c131d2d3 - //TODO: VPSRLD (BX), X9, X11 // c46131d21b or c531d21b - //TODO: VPSRLD (R11), X9, X11 // c44131d21b - //TODO: VPSRLD X2, X9, X11 // c46131d2da or c531d2da - //TODO: VPSRLD X11, X9, X11 // c44131d2db - //TODO: VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207 - //TODO: VPSRLD $7, X11, X9 // c4c13172d307 - //TODO: VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07 - //TODO: VPSRLDQ $7, X11, X9 // c4c13173db07 - //TODO: VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07 - //TODO: VPSRLDQ $7, Y11, Y15 // c4c10573db07 - //TODO: VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313 - //TODO: VPSRLQ (R11), X9, X2 // c4c131d313 - //TODO: VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2 - //TODO: VPSRLQ X11, X9, X2 // c4c131d3d3 - //TODO: VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b - //TODO: VPSRLQ (R11), X9, X11 // c44131d31b - //TODO: VPSRLQ X2, X9, X11 // c46131d3da or c531d3da - //TODO: VPSRLQ X11, X9, X11 // c44131d3db - //TODO: VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207 - //TODO: VPSRLQ $7, X11, X9 // c4c13173d307 + VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213 + VPSRLD (R11), X9, X2 // c4c131d213 + VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2 + VPSRLD X11, X9, X2 // c4c131d2d3 + VPSRLD (BX), X9, X11 // c46131d21b or c531d21b + VPSRLD (R11), X9, X11 // c44131d21b + VPSRLD X2, X9, X11 // c46131d2da or c531d2da + VPSRLD X11, X9, X11 // c44131d2db + VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207 + VPSRLD $7, X11, X9 // c4c13172d307 + VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07 + VPSRLDQ $7, X11, X9 // c4c13173db07 + VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07 + VPSRLDQ $7, Y11, Y15 // c4c10573db07 + VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313 + VPSRLQ (R11), X9, X2 // c4c131d313 + VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2 + VPSRLQ X11, X9, X2 // c4c131d3d3 + VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b + VPSRLQ (R11), X9, X11 // c44131d31b + VPSRLQ X2, X9, X11 // c46131d3da or c531d3da + VPSRLQ X11, X9, X11 // c44131d3db + VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207 + VPSRLQ $7, X11, X9 // c4c13173d307 //TODO: VPSRLVD (BX), X9, X2 // c4e2314513 //TODO: VPSRLVD (R11), X9, X2 // c4c2314513 //TODO: VPSRLVD X2, X9, X2 // c4e23145d2 diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 294cedcb0a25a3..18813c35a8ea3e 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -140,6 +140,11 @@ func (p *Prog) String() string { fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(p.As), sc) sep := "\t" + quadOpAmd64 := p.RegTo2 == -1 + if quadOpAmd64 { + fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset) + sep = ", " + } if p.From.Type != TYPE_NONE { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) sep = ", " @@ -153,6 +158,8 @@ func (p *Prog) String() string { if p.From3.Type == TYPE_CONST && (p.As == ATEXT || p.As == AGLOBL) { // Special case - omit $. fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset) + } else if quadOpAmd64 { + fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg))) } else { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3)) } @@ -161,7 +168,7 @@ func (p *Prog) String() string { if p.To.Type != TYPE_NONE { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) } - if p.RegTo2 != REG_NONE { + if p.RegTo2 != REG_NONE && !quadOpAmd64 { fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) } return buf.String() diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go index f00e4afdb8f7ac..ab1dabc2b89735 100644 --- a/src/cmd/internal/obj/x86/a.out.go +++ b/src/cmd/internal/obj/x86/a.out.go @@ -785,6 +785,24 @@ const ( AVPAND AVPTEST AVPBROADCASTB + AVPSHUFB + AVPSHUFD + AVPERM2F128 + AVPALIGNR + AVPADDQ + AVPADDD + AVPSRLDQ + AVPSLLDQ + AVPSRLQ + AVPSLLQ + AVPSRLD + AVPSLLD + AVPOR + AVPBLENDD + AVINSERTI128 + AVPERM2I128 + ARORXL + ARORXQ // from 386 AJCXZW diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go index e3fef54e717510..3b301546258431 100644 --- a/src/cmd/internal/obj/x86/anames.go +++ b/src/cmd/internal/obj/x86/anames.go @@ -720,6 +720,24 @@ var Anames = []string{ "VPAND", "VPTEST", "VPBROADCASTB", + "VPSHUFB", + "VPSHUFD", + "VPERM2F128", + "VPALIGNR", + "VPADDQ", + "VPADDD", + "VPSRLDQ", + "VPSLLDQ", + "VPSRLQ", + "VPSLLQ", + "VPSRLD", + "VPSLLD", + "VPOR", + "VPBLENDD", + "VINSERTI128", + "VPERM2I128", + "RORXL", + "RORXQ", "JCXZW", "FCMOVCC", "FCMOVCS", diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 8605980b94d996..9230c9fdacb1da 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -208,6 +208,9 @@ const ( Zvex_rm_v_r Zvex_r_v_rm Zvex_v_rm_r + Zvex_i_rm_r + Zvex_i_r_v + Zvex_i_rm_v_r Zmax ) @@ -847,6 +850,35 @@ var yvex_xy3 = []ytab{ {Yym, Yyr, Yyr, Zvex_rm_v_r, 2}, } +var yvex_ri3 = []ytab{ + {Yi8, Ymb, Yrl, Zvex_i_rm_r, 2}, +} + +var yvex_xyi3 = []ytab{ + {Yi8, Yxm, Yxr, Zvex_i_rm_r, 2}, + {Yi8, Yym, Yyr, Zvex_i_rm_r, 2}, +} + +var yvex_yyi4 = []ytab{ //TODO don't hide 4 op, some version have xmm version + {Yym, Yyr, Yyr, Zvex_i_rm_v_r, 2}, +} + +var yvex_xyi4 = []ytab{ + {Yxm, Yyr, Yyr, Zvex_i_rm_v_r, 2}, +} + +var yvex_shift = []ytab{ + {Yi8, Yxr, Yxr, Zvex_i_r_v, 3}, + {Yi8, Yyr, Yyr, Zvex_i_r_v, 3}, + {Yxm, Yxr, Yxr, Zvex_rm_v_r, 2}, + {Yxm, Yyr, Yyr, Zvex_rm_v_r, 2}, +} + +var yvex_shift_dq = []ytab{ + {Yi8, Yxr, Yxr, Zvex_i_r_v, 3}, + {Yi8, Yyr, Yyr, Zvex_i_r_v, 3}, +} + var yvex_r3 = []ytab{ {Yml, Yrl, Yrl, Zvex_rm_v_r, 2}, {Yml, Yrl, Yrl, Zvex_rm_v_r, 2}, @@ -1679,6 +1711,24 @@ var optab = {AVPAND, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xDB, VEX_256_66_0F_WIG, 0xDB}}, {AVPBROADCASTB, yvex_vpbroadcast, Pvex, [23]uint8{VEX_128_66_0F38_W0, 0x78, VEX_256_66_0F38_W0, 0x78}}, {AVPTEST, yvex_xy2, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x17, VEX_256_66_0F38_WIG, 0x17}}, + {AVPSHUFB, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x00, VEX_256_66_0F38_WIG, 0x00}}, + {AVPSHUFD, yvex_xyi3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70}}, + {AVPOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xeb, VEX_256_66_0F_WIG, 0xeb}}, + {AVPADDQ, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xd4, VEX_256_66_0F_WIG, 0xd4}}, + {AVPADDD, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xfe, VEX_256_66_0F_WIG, 0xfe}}, + {AVPSLLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xf0, VEX_256_66_0F_WIG, 0x72, 0xf0, VEX_128_66_0F_WIG, 0xf2, VEX_256_66_0F_WIG, 0xf2}}, + {AVPSLLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf0, VEX_256_66_0F_WIG, 0x73, 0xf0, VEX_128_66_0F_WIG, 0xf3, VEX_256_66_0F_WIG, 0xf3}}, + {AVPSRLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xd0, VEX_256_66_0F_WIG, 0x72, 0xd0, VEX_128_66_0F_WIG, 0xd2, VEX_256_66_0F_WIG, 0xd2}}, + {AVPSRLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd0, VEX_256_66_0F_WIG, 0x73, 0xd0, VEX_128_66_0F_WIG, 0xd3, VEX_256_66_0F_WIG, 0xd3}}, + {AVPSRLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd8, VEX_256_66_0F_WIG, 0x73, 0xd8}}, + {AVPSLLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf8, VEX_256_66_0F_WIG, 0x73, 0xf8}}, + {AVPERM2F128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_W0, 0x06}}, + {AVPALIGNR, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x0f}}, + {AVPBLENDD, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x02}}, + {AVINSERTI128, yvex_xyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x38}}, + {AVPERM2I128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x46}}, + {ARORXL, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W0, 0xf0}}, + {ARORXQ, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W1, 0xf0}}, {AXACQUIRE, ynone, Px, [23]uint8{0xf2}}, {AXRELEASE, ynone, Px, [23]uint8{0xf3}}, @@ -3189,9 +3239,16 @@ var bpduff2 = []byte{ // https://en.wikipedia.org/wiki/VEX_prefix#Technical_description func asmvex(ctxt *obj.Link, rm, v, r *obj.Addr, vex, opcode uint8) { ctxt.Vexflag = 1 - rexR := regrex[r.Reg] & Rxr - rexB := regrex[rm.Reg] & Rxb - rexX := regrex[rm.Index] & Rxx + rexR := 0 + if r != nil { + rexR = regrex[r.Reg] & Rxr + } + rexB := 0 + rexX := 0 + if rm != nil { + rexB = regrex[rm.Reg] & Rxb + rexX = regrex[rm.Index] & Rxx + } vexM := (vex >> 3) & 0xF vexWLP := vex & 0x87 vexV := byte(0) @@ -3477,6 +3534,27 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1]) asmand(ctxt, p, &p.From, &p.To) + case Zvex_i_r_v: + asmvex(ctxt, p.From3, &p.To, nil, o.op[z], o.op[z+1]) + regnum := byte(0x7) + if p.From3.Reg >= REG_X0 && p.From3.Reg <= REG_X15 { + regnum &= byte(p.From3.Reg - REG_X0) + } else { + regnum &= byte(p.From3.Reg - REG_Y0) + } + ctxt.AsmBuf.Put1(byte(o.op[z+2]) | regnum) + ctxt.AsmBuf.Put1(byte(p.From.Offset)) + + case Zvex_i_rm_v_r: + asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1]) + asmand(ctxt, p, &p.From, &p.To) + ctxt.AsmBuf.Put1(byte(p.From3.Offset)) + + case Zvex_i_rm_r: + asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1]) + asmand(ctxt, p, p.From3, &p.To) + ctxt.AsmBuf.Put1(byte(p.From.Offset)) + case Zvex_v_rm_r: asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1]) asmand(ctxt, p, p.From3, &p.To) From e558fdbd9a3865dd383f50524bb8a18b9e6a0cb0 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 6 May 2016 15:09:57 +0200 Subject: [PATCH 014/267] misc/cgo/testcarchive: don't force -no_pie on Darwin Now that darwin/arm supports position independent code, allow the binaries generated by the c-archive tests be position independent (PIE) as well. Change-Id: If0517f06e92349ada29a4e3e0a951f08b0fcc710 Reviewed-on: https://go-review.googlesource.com/22841 Reviewed-by: David Crawshaw Run-TryBot: Elias Naur TryBot-Result: Gobot Gobot --- misc/cgo/testcarchive/carchive_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go index c0c45398cda9db..0174e310156928 100644 --- a/misc/cgo/testcarchive/carchive_test.go +++ b/misc/cgo/testcarchive/carchive_test.go @@ -79,8 +79,6 @@ func init() { } if GOOS == "darwin" { - cc = append(cc, "-Wl,-no_pie") - // For Darwin/ARM. // TODO(crawshaw): can we do better? cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) From 2210d88a889e0ea463bcdef2b658aaec1050cf01 Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Fri, 29 Apr 2016 16:19:17 +0300 Subject: [PATCH 015/267] crypto/sha256: Use AVX2 if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta Hash8Bytes-4 376ns ± 0% 246ns ± 0% -34.57% (p=0.000 n=20+20) Hash1K-4 5.21µs ± 0% 2.82µs ± 0% -45.83% (p=0.000 n=20+20) Hash8K-4 38.6µs ± 0% 20.8µs ± 0% -46.05% (p=0.000 n=20+20) name old speed new speed delta Hash8Bytes-4 21.2MB/s ± 0% 32.4MB/s ± 0% +52.70% (p=0.000 n=15+19) Hash1K-4 197MB/s ± 0% 363MB/s ± 0% +84.60% (p=0.000 n=20+20) Hash8K-4 212MB/s ± 0% 393MB/s ± 0% +85.36% (p=0.000 n=20+20) Change-Id: Ib50119c591074ff486d11d3566e24b691bcc6598 Reviewed-on: https://go-review.googlesource.com/22608 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/crypto/sha256/sha256block_amd64.s | 873 ++++++++++++++++++++++++-- 1 file changed, 829 insertions(+), 44 deletions(-) diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s index c9f134c1069082..6ab3b52d65e163 100644 --- a/src/crypto/sha256/sha256block_amd64.s +++ b/src/crypto/sha256/sha256block_amd64.s @@ -1,4 +1,4 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -9,7 +9,18 @@ // The algorithm is detailed in FIPS 180-4: // // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf -// + +// The avx2-version is described in an Intel White-Paper: +// "Fast SHA-256 Implementations on Intel Architecture Processors" +// To find it, surf to http://www.intel.com/p/en_US/embedded +// and search for that title. +// AVX2 version by Intel, same algorithm as code in Linux kernel: +// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha256-avx2-asm.S +// by +// James Guilford +// Kirk Yap +// Tim Chen + // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 // @@ -140,29 +151,439 @@ MSGSCHEDULE1(index); \ SHA256ROUND(index, const, a, b, c, d, e, f, g, h) -TEXT ·block(SB),0,$264-32 - MOVQ p_base+8(FP), SI - MOVQ p_len+16(FP), DX - SHRQ $6, DX - SHLQ $6, DX - - LEAQ (SI)(DX*1), DI - MOVQ DI, 256(SP) - CMPQ SI, DI - JEQ end - - MOVQ dig+0(FP), BP - MOVL (0*4)(BP), R8 // a = H0 - MOVL (1*4)(BP), R9 // b = H1 - MOVL (2*4)(BP), R10 // c = H2 - MOVL (3*4)(BP), R11 // d = H3 - MOVL (4*4)(BP), R12 // e = H4 - MOVL (5*4)(BP), R13 // f = H5 - MOVL (6*4)(BP), R14 // g = H6 - MOVL (7*4)(BP), R15 // h = H7 + +// Definitions for AVX2 version + +// addm (mem), reg +// Add reg to mem using reg-mem add and store +#define addm(P1, P2) \ + ADDL P2, P1; \ + MOVL P1, P2 + +#define XDWORD0 Y4 +#define XDWORD1 Y5 +#define XDWORD2 Y6 +#define XDWORD3 Y7 + +#define XWORD0 X4 +#define XWORD1 X5 +#define XWORD2 X6 +#define XWORD3 X7 + +#define XTMP0 Y0 +#define XTMP1 Y1 +#define XTMP2 Y2 +#define XTMP3 Y3 +#define XTMP4 Y8 +#define XTMP5 Y11 + +#define XFER Y9 + +#define BYTE_FLIP_MASK Y13 // mask to convert LE -> BE +#define X_BYTE_FLIP_MASK X13 + +#define NUM_BYTES DX +#define INP DI + +#define CTX SI // Beginning of digest in memory (a, b, c, ... , h) + +#define a AX +#define b BX +#define c CX +#define d R8 +#define e DX +#define f R9 +#define g R10 +#define h R11 + +#define old_h R11 + +#define TBL BP + +#define SRND SI // SRND is same register as CTX + +#define T1 R12 + +#define y0 R13 +#define y1 R14 +#define y2 R15 +#define y3 DI + +// Offsets +#define XFER_SIZE 2*64*4 +#define INP_END_SIZE 8 +#define INP_SIZE 8 +#define TMP_SIZE 4 + +#define _XFER 0 +#define _INP_END _XFER + XFER_SIZE +#define _INP _INP_END + INP_END_SIZE +#define _TMP _INP + INP_SIZE +#define STACK_SIZE _TMP + TMP_SIZE + +#define ROUND_AND_SCHED_N_0(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ############################# RND N + 0 ############################// + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ; \ + ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // disp = k + w + ORL c, y3; \ // y3 = a|c // MAJA + VPALIGNR $4, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-7] + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + VPADDD XDWORD0, XTMP0, XTMP0; \ // XTMP0 = W[-7] + W[-16] // y1 = (e >> 6) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ; \ + ANDL e, y2; \ // y2 = (f^g)&e // CH + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ADDL h, d; \ // d = k + w + h + d // -- + ; \ + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + VPALIGNR $4, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-15] + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ; \ + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + VPSRLD $7, XTMP1, XTMP2; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ; \ + ADDL y0, y2; \ // y2 = S1 + CH // -- + VPSLLD $(32-7), XTMP1, XTMP3; \ + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + VPOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 + ; \ + VPSRLD $18, XTMP1, XTMP2; \ + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define ROUND_AND_SCHED_N_1(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 1 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + VPSRLD $3, XTMP1, XTMP4; \ // XTMP4 = W[-15] >> 3 + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + ; \ + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL h, d; \ // d = k + w + h + d // -- + ; \ + VPSLLD $(32-18), XTMP1, XTMP1; \ + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + ; \ + VPXOR XTMP1, XTMP3, XTMP3; \ + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + VPXOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 ^ W[-15] ror 18 + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + VPXOR XTMP4, XTMP3, XTMP1; \ // XTMP1 = s0 + VPSHUFD $-6, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA} + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + VPADDD XTMP1, XTMP0, XTMP0; \ // XTMP0 = W[-16] + W[-7] + s0 + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h; \ // h = t1 + S0 + MAJ // -- + ; \ + VPSRLD $10, XTMP2, XTMP4 // XTMP4 = W[-2] >> 10 {BBAA} + +#define ROUND_AND_SCHED_N_2(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 2 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ; \ + VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xBxA} + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ORL c, y3; \ // y3 = a|c // MAJA + MOVL f, y2; \ // y2 = f // CH + XORL g, y2; \ // y2 = f^g // CH + ; \ + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xBxA} + ANDL e, y2; \ // y2 = (f^g)&e // CH + ; \ + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + VPXOR XTMP3, XTMP2, XTMP2; \ + ADDL h, d; \ // d = k + w + h + d // -- + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + VPXOR XTMP2, XTMP4, XTMP4; \ // XTMP4 = s1 {xBxA} + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + MOVL f, _TMP(SP); \ + MOVQ $shuff_00BA<>(SB), f; \ // f is used to keep SHUF_00BA + VPSHUFB (f), XTMP4, XTMP4; \ // XTMP4 = s1 {00BA} + MOVL _TMP(SP), f; \ // f is restored + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + VPADDD XTMP4, XTMP0, XTMP0; \ // XTMP0 = {..., ..., W[1], W[0]} + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + VPSHUFD $80, XTMP0, XTMP2; \ // XTMP2 = W[-2] {DDCC} + ; \ + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ; \ + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define ROUND_AND_SCHED_N_3(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 3 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + VPSRLD $10, XTMP2, XTMP5; \ // XTMP5 = W[-2] >> 10 {DDCC} + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + ; \ + VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xDxC} + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL h, d; \ // d = k + w + h + d // -- + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ; \ + VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xDxC} + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + VPXOR XTMP3, XTMP2, XTMP2; \ + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + VPXOR XTMP2, XTMP5, XTMP5; \ // XTMP5 = s1 {xDxC} + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ; \ + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ; \ + MOVL f, _TMP(SP); \ // Save f + MOVQ $shuff_DC00<>(SB), f; \ // SHUF_00DC + VPSHUFB (f), XTMP5, XTMP5; \ // XTMP5 = s1 {DC00} + MOVL _TMP(SP), f; \ // Restore f + ; \ + VPADDD XTMP0, XTMP5, XDWORD0; \ // XDWORD0 = {W[3], W[2], W[1], W[0]} + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ; \ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define DO_ROUND_N_0(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 0 ########################### + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_1(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 1 ########################### + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0 // -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_2(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 2 ############################## + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_3(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 3 ########################### + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ; \ + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ; \ + ADDL y3, h // h = t1 + S0 + MAJ // -- + +TEXT ·block(SB), 0, $536-32 + CMPB runtime·support_avx2(SB), $1 + JE avx2 + + MOVQ p_base+8(FP), SI + MOVQ p_len+16(FP), DX + SHRQ $6, DX + SHLQ $6, DX + + LEAQ (SI)(DX*1), DI + MOVQ DI, 256(SP) + CMPQ SI, DI + JEQ end + + MOVQ dig+0(FP), BP + MOVL (0*4)(BP), R8 // a = H0 + MOVL (1*4)(BP), R9 // b = H1 + MOVL (2*4)(BP), R10 // c = H2 + MOVL (3*4)(BP), R11 // d = H3 + MOVL (4*4)(BP), R12 // e = H4 + MOVL (5*4)(BP), R13 // f = H5 + MOVL (6*4)(BP), R14 // g = H6 + MOVL (7*4)(BP), R15 // h = H7 loop: - MOVQ SP, BP // message schedule + MOVQ SP, BP SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14) @@ -230,27 +651,391 @@ loop: SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8) - MOVQ dig+0(FP), BP - ADDL (0*4)(BP), R8 // H0 = a + H0 - MOVL R8, (0*4)(BP) - ADDL (1*4)(BP), R9 // H1 = b + H1 - MOVL R9, (1*4)(BP) - ADDL (2*4)(BP), R10 // H2 = c + H2 - MOVL R10, (2*4)(BP) - ADDL (3*4)(BP), R11 // H3 = d + H3 - MOVL R11, (3*4)(BP) - ADDL (4*4)(BP), R12 // H4 = e + H4 - MOVL R12, (4*4)(BP) - ADDL (5*4)(BP), R13 // H5 = f + H5 - MOVL R13, (5*4)(BP) - ADDL (6*4)(BP), R14 // H6 = g + H6 - MOVL R14, (6*4)(BP) - ADDL (7*4)(BP), R15 // H7 = h + H7 - MOVL R15, (7*4)(BP) - - ADDQ $64, SI - CMPQ SI, 256(SP) - JB loop + MOVQ dig+0(FP), BP + ADDL (0*4)(BP), R8 // H0 = a + H0 + MOVL R8, (0*4)(BP) + ADDL (1*4)(BP), R9 // H1 = b + H1 + MOVL R9, (1*4)(BP) + ADDL (2*4)(BP), R10 // H2 = c + H2 + MOVL R10, (2*4)(BP) + ADDL (3*4)(BP), R11 // H3 = d + H3 + MOVL R11, (3*4)(BP) + ADDL (4*4)(BP), R12 // H4 = e + H4 + MOVL R12, (4*4)(BP) + ADDL (5*4)(BP), R13 // H5 = f + H5 + MOVL R13, (5*4)(BP) + ADDL (6*4)(BP), R14 // H6 = g + H6 + MOVL R14, (6*4)(BP) + ADDL (7*4)(BP), R15 // H7 = h + H7 + MOVL R15, (7*4)(BP) + + ADDQ $64, SI + CMPQ SI, 256(SP) + JB loop end: RET + +avx2: + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ p_base+8(FP), INP + MOVQ p_len+16(FP), NUM_BYTES + + LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block + MOVQ NUM_BYTES, _INP_END(SP) + + CMPQ NUM_BYTES, INP + JE avx2_only_one_block + + // Load initial digest + MOVL 0(CTX), a // a = H0 + MOVL 4(CTX), b // b = H1 + MOVL 8(CTX), c // c = H2 + MOVL 12(CTX), d // d = H3 + MOVL 16(CTX), e // e = H4 + MOVL 20(CTX), f // f = H5 + MOVL 24(CTX), g // g = H6 + MOVL 28(CTX), h // h = H7 + +avx2_loop0: // at each iteration works with one block (512 bit) + + VMOVDQU (0*32)(INP), XTMP0 + VMOVDQU (1*32)(INP), XTMP1 + VMOVDQU (2*32)(INP), XTMP2 + VMOVDQU (3*32)(INP), XTMP3 + + MOVQ $flip_mask<>(SB), BP // BYTE_FLIP_MASK + VMOVDQU (BP), BYTE_FLIP_MASK + + // Apply Byte Flip Mask: LE -> BE + VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0 + VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1 + VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2 + VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3 + + // Transpose data into high/low parts + VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0 + VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4 + VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8 + VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12 + + MOVQ $K256<>(SB), TBL // Loading address of table with round-specific constants + +avx2_last_block_enter: + ADDQ $64, INP + MOVQ INP, _INP(SP) + XORQ SRND, SRND + +avx2_loop1: // for w0 - w47 + // Do 4 rounds and scheduling + VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER + VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + + // Do 4 rounds and scheduling + VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER + VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + + // Do 4 rounds and scheduling + VPADDD 2*32(TBL)(SRND*1), XDWORD2, XFER + VMOVDQU XFER, (_XFER + 2*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 2*32, a, b, c, d, e, f, g, h, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_1(_XFER + 2*32, h, a, b, c, d, e, f, g, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_2(_XFER + 2*32, g, h, a, b, c, d, e, f, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_3(_XFER + 2*32, f, g, h, a, b, c, d, e, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + + // Do 4 rounds and scheduling + VPADDD 3*32(TBL)(SRND*1), XDWORD3, XFER + VMOVDQU XFER, (_XFER + 3*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 3*32, e, f, g, h, a, b, c, d, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_1(_XFER + 3*32, d, e, f, g, h, a, b, c, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_2(_XFER + 3*32, c, d, e, f, g, h, a, b, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_3(_XFER + 3*32, b, c, d, e, f, g, h, a, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + + ADDQ $4*32, SRND + CMPQ SRND, $3*4*32 + JB avx2_loop1 + +avx2_loop2: + // w48 - w63 processed with no scheduliung (last 16 rounds) + VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER + VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) + DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h) + DO_ROUND_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, h) + DO_ROUND_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, g) + DO_ROUND_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, f) + + VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER + VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1) + DO_ROUND_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, e) + DO_ROUND_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, d) + DO_ROUND_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, c) + DO_ROUND_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, b) + + ADDQ $2*32, SRND + + VMOVDQU XDWORD2, XDWORD0 + VMOVDQU XDWORD3, XDWORD1 + + CMPQ SRND, $4*4*32 + JB avx2_loop2 + + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ _INP(SP), INP + + addm( 0(CTX), a) + addm( 4(CTX), b) + addm( 8(CTX), c) + addm( 12(CTX), d) + addm( 16(CTX), e) + addm( 20(CTX), f) + addm( 24(CTX), g) + addm( 28(CTX), h) + + CMPQ _INP_END(SP), INP + JB done_hash + + XORQ SRND, SRND + +avx2_loop3: // Do second block using previously scheduled results + DO_ROUND_N_0(_XFER + 0*32 + 16, a, b, c, d, e, f, g, h, a) + DO_ROUND_N_1(_XFER + 0*32 + 16, h, a, b, c, d, e, f, g, h) + DO_ROUND_N_2(_XFER + 0*32 + 16, g, h, a, b, c, d, e, f, g) + DO_ROUND_N_3(_XFER + 0*32 + 16, f, g, h, a, b, c, d, e, f) + + DO_ROUND_N_0(_XFER + 1*32 + 16, e, f, g, h, a, b, c, d, e) + DO_ROUND_N_1(_XFER + 1*32 + 16, d, e, f, g, h, a, b, c, d) + DO_ROUND_N_2(_XFER + 1*32 + 16, c, d, e, f, g, h, a, b, c) + DO_ROUND_N_3(_XFER + 1*32 + 16, b, c, d, e, f, g, h, a, b) + + ADDQ $2*32, SRND + CMPQ SRND, $4*4*32 + JB avx2_loop3 + + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ _INP(SP), INP + ADDQ $64, INP + + addm( 0(CTX), a) + addm( 4(CTX), b) + addm( 8(CTX), c) + addm( 12(CTX), d) + addm( 16(CTX), e) + addm( 20(CTX), f) + addm( 24(CTX), g) + addm( 28(CTX), h) + + CMPQ _INP_END(SP), INP + JA avx2_loop0 + JB done_hash + +avx2_do_last_block: + + VMOVDQU 0(INP), XWORD0 + VMOVDQU 16(INP), XWORD1 + VMOVDQU 32(INP), XWORD2 + VMOVDQU 48(INP), XWORD3 + + MOVQ $flip_mask<>(SB), BP + VMOVDQU (BP), X_BYTE_FLIP_MASK + + VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0 + VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1 + VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2 + VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3 + + MOVQ $K256<>(SB), TBL + + JMP avx2_last_block_enter + +avx2_only_one_block: + // Load initial digest + MOVL 0(CTX), a // a = H0 + MOVL 4(CTX), b // b = H1 + MOVL 8(CTX), c // c = H2 + MOVL 12(CTX), d // d = H3 + MOVL 16(CTX), e // e = H4 + MOVL 20(CTX), f // f = H5 + MOVL 24(CTX), g // g = H6 + MOVL 28(CTX), h // h = H7 + + JMP avx2_do_last_block + +done_hash: + VZEROUPPER + RET + +// shuffle byte order from LE to BE +DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203 +DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b +DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203 +DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b +GLOBL flip_mask<>(SB), 8, $32 + +// shuffle xBxA -> 00BA +DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100 +DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100 +DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF +GLOBL shuff_00BA<>(SB), 8, $32 + +// shuffle xDxC -> DC00 +DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100 +DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100 +GLOBL shuff_DC00<>(SB), 8, $32 + +// Round specific constants +DATA K256<>+0x00(SB)/4, $0x428a2f98 // k1 +DATA K256<>+0x04(SB)/4, $0x71374491 // k2 +DATA K256<>+0x08(SB)/4, $0xb5c0fbcf // k3 +DATA K256<>+0x0c(SB)/4, $0xe9b5dba5 // k4 +DATA K256<>+0x10(SB)/4, $0x428a2f98 // k1 +DATA K256<>+0x14(SB)/4, $0x71374491 // k2 +DATA K256<>+0x18(SB)/4, $0xb5c0fbcf // k3 +DATA K256<>+0x1c(SB)/4, $0xe9b5dba5 // k4 + +DATA K256<>+0x20(SB)/4, $0x3956c25b // k5 - k8 +DATA K256<>+0x24(SB)/4, $0x59f111f1 +DATA K256<>+0x28(SB)/4, $0x923f82a4 +DATA K256<>+0x2c(SB)/4, $0xab1c5ed5 +DATA K256<>+0x30(SB)/4, $0x3956c25b +DATA K256<>+0x34(SB)/4, $0x59f111f1 +DATA K256<>+0x38(SB)/4, $0x923f82a4 +DATA K256<>+0x3c(SB)/4, $0xab1c5ed5 + +DATA K256<>+0x40(SB)/4, $0xd807aa98 // k9 - k12 +DATA K256<>+0x44(SB)/4, $0x12835b01 +DATA K256<>+0x48(SB)/4, $0x243185be +DATA K256<>+0x4c(SB)/4, $0x550c7dc3 +DATA K256<>+0x50(SB)/4, $0xd807aa98 +DATA K256<>+0x54(SB)/4, $0x12835b01 +DATA K256<>+0x58(SB)/4, $0x243185be +DATA K256<>+0x5c(SB)/4, $0x550c7dc3 + +DATA K256<>+0x60(SB)/4, $0x72be5d74 // k13 - k16 +DATA K256<>+0x64(SB)/4, $0x80deb1fe +DATA K256<>+0x68(SB)/4, $0x9bdc06a7 +DATA K256<>+0x6c(SB)/4, $0xc19bf174 +DATA K256<>+0x70(SB)/4, $0x72be5d74 +DATA K256<>+0x74(SB)/4, $0x80deb1fe +DATA K256<>+0x78(SB)/4, $0x9bdc06a7 +DATA K256<>+0x7c(SB)/4, $0xc19bf174 + +DATA K256<>+0x80(SB)/4, $0xe49b69c1 // k17 - k20 +DATA K256<>+0x84(SB)/4, $0xefbe4786 +DATA K256<>+0x88(SB)/4, $0x0fc19dc6 +DATA K256<>+0x8c(SB)/4, $0x240ca1cc +DATA K256<>+0x90(SB)/4, $0xe49b69c1 +DATA K256<>+0x94(SB)/4, $0xefbe4786 +DATA K256<>+0x98(SB)/4, $0x0fc19dc6 +DATA K256<>+0x9c(SB)/4, $0x240ca1cc + +DATA K256<>+0xa0(SB)/4, $0x2de92c6f // k21 - k24 +DATA K256<>+0xa4(SB)/4, $0x4a7484aa +DATA K256<>+0xa8(SB)/4, $0x5cb0a9dc +DATA K256<>+0xac(SB)/4, $0x76f988da +DATA K256<>+0xb0(SB)/4, $0x2de92c6f +DATA K256<>+0xb4(SB)/4, $0x4a7484aa +DATA K256<>+0xb8(SB)/4, $0x5cb0a9dc +DATA K256<>+0xbc(SB)/4, $0x76f988da + +DATA K256<>+0xc0(SB)/4, $0x983e5152 // k25 - k28 +DATA K256<>+0xc4(SB)/4, $0xa831c66d +DATA K256<>+0xc8(SB)/4, $0xb00327c8 +DATA K256<>+0xcc(SB)/4, $0xbf597fc7 +DATA K256<>+0xd0(SB)/4, $0x983e5152 +DATA K256<>+0xd4(SB)/4, $0xa831c66d +DATA K256<>+0xd8(SB)/4, $0xb00327c8 +DATA K256<>+0xdc(SB)/4, $0xbf597fc7 + +DATA K256<>+0xe0(SB)/4, $0xc6e00bf3 // k29 - k32 +DATA K256<>+0xe4(SB)/4, $0xd5a79147 +DATA K256<>+0xe8(SB)/4, $0x06ca6351 +DATA K256<>+0xec(SB)/4, $0x14292967 +DATA K256<>+0xf0(SB)/4, $0xc6e00bf3 +DATA K256<>+0xf4(SB)/4, $0xd5a79147 +DATA K256<>+0xf8(SB)/4, $0x06ca6351 +DATA K256<>+0xfc(SB)/4, $0x14292967 + +DATA K256<>+0x100(SB)/4, $0x27b70a85 +DATA K256<>+0x104(SB)/4, $0x2e1b2138 +DATA K256<>+0x108(SB)/4, $0x4d2c6dfc +DATA K256<>+0x10c(SB)/4, $0x53380d13 +DATA K256<>+0x110(SB)/4, $0x27b70a85 +DATA K256<>+0x114(SB)/4, $0x2e1b2138 +DATA K256<>+0x118(SB)/4, $0x4d2c6dfc +DATA K256<>+0x11c(SB)/4, $0x53380d13 + +DATA K256<>+0x120(SB)/4, $0x650a7354 +DATA K256<>+0x124(SB)/4, $0x766a0abb +DATA K256<>+0x128(SB)/4, $0x81c2c92e +DATA K256<>+0x12c(SB)/4, $0x92722c85 +DATA K256<>+0x130(SB)/4, $0x650a7354 +DATA K256<>+0x134(SB)/4, $0x766a0abb +DATA K256<>+0x138(SB)/4, $0x81c2c92e +DATA K256<>+0x13c(SB)/4, $0x92722c85 + +DATA K256<>+0x140(SB)/4, $0xa2bfe8a1 +DATA K256<>+0x144(SB)/4, $0xa81a664b +DATA K256<>+0x148(SB)/4, $0xc24b8b70 +DATA K256<>+0x14c(SB)/4, $0xc76c51a3 +DATA K256<>+0x150(SB)/4, $0xa2bfe8a1 +DATA K256<>+0x154(SB)/4, $0xa81a664b +DATA K256<>+0x158(SB)/4, $0xc24b8b70 +DATA K256<>+0x15c(SB)/4, $0xc76c51a3 + +DATA K256<>+0x160(SB)/4, $0xd192e819 +DATA K256<>+0x164(SB)/4, $0xd6990624 +DATA K256<>+0x168(SB)/4, $0xf40e3585 +DATA K256<>+0x16c(SB)/4, $0x106aa070 +DATA K256<>+0x170(SB)/4, $0xd192e819 +DATA K256<>+0x174(SB)/4, $0xd6990624 +DATA K256<>+0x178(SB)/4, $0xf40e3585 +DATA K256<>+0x17c(SB)/4, $0x106aa070 + +DATA K256<>+0x180(SB)/4, $0x19a4c116 +DATA K256<>+0x184(SB)/4, $0x1e376c08 +DATA K256<>+0x188(SB)/4, $0x2748774c +DATA K256<>+0x18c(SB)/4, $0x34b0bcb5 +DATA K256<>+0x190(SB)/4, $0x19a4c116 +DATA K256<>+0x194(SB)/4, $0x1e376c08 +DATA K256<>+0x198(SB)/4, $0x2748774c +DATA K256<>+0x19c(SB)/4, $0x34b0bcb5 + +DATA K256<>+0x1a0(SB)/4, $0x391c0cb3 +DATA K256<>+0x1a4(SB)/4, $0x4ed8aa4a +DATA K256<>+0x1a8(SB)/4, $0x5b9cca4f +DATA K256<>+0x1ac(SB)/4, $0x682e6ff3 +DATA K256<>+0x1b0(SB)/4, $0x391c0cb3 +DATA K256<>+0x1b4(SB)/4, $0x4ed8aa4a +DATA K256<>+0x1b8(SB)/4, $0x5b9cca4f +DATA K256<>+0x1bc(SB)/4, $0x682e6ff3 + +DATA K256<>+0x1c0(SB)/4, $0x748f82ee +DATA K256<>+0x1c4(SB)/4, $0x78a5636f +DATA K256<>+0x1c8(SB)/4, $0x84c87814 +DATA K256<>+0x1cc(SB)/4, $0x8cc70208 +DATA K256<>+0x1d0(SB)/4, $0x748f82ee +DATA K256<>+0x1d4(SB)/4, $0x78a5636f +DATA K256<>+0x1d8(SB)/4, $0x84c87814 +DATA K256<>+0x1dc(SB)/4, $0x8cc70208 + +DATA K256<>+0x1e0(SB)/4, $0x90befffa +DATA K256<>+0x1e4(SB)/4, $0xa4506ceb +DATA K256<>+0x1e8(SB)/4, $0xbef9a3f7 +DATA K256<>+0x1ec(SB)/4, $0xc67178f2 +DATA K256<>+0x1f0(SB)/4, $0x90befffa +DATA K256<>+0x1f4(SB)/4, $0xa4506ceb +DATA K256<>+0x1f8(SB)/4, $0xbef9a3f7 +DATA K256<>+0x1fc(SB)/4, $0xc67178f2 + +GLOBL K256<>(SB), (NOPTR + RODATA), $512 From fafadc521ede90f8abed73e8d209e130c456e983 Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Fri, 29 Apr 2016 16:17:14 +0300 Subject: [PATCH 016/267] crypto/sha1: Add AVX2 version for AMD64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta Hash8Bytes-48 271ns ± 8% 273ns ± 5% ~ (p=0.313 n=19+19) Hash320Bytes-48 1.04µs ± 7% 0.75µs ± 8% -27.66% (p=0.000 n=20+20) Hash1K-48 2.72µs ± 6% 1.75µs ± 6% -35.79% (p=0.000 n=19+20) Hash8K-48 19.9µs ± 7% 11.6µs ± 6% -41.84% (p=0.000 n=20+19) name old speed new speed delta Hash8Bytes-48 29.5MB/s ± 8% 29.3MB/s ± 5% ~ (p=0.314 n=19+19) Hash320Bytes-48 307MB/s ± 7% 424MB/s ± 8% +38.29% (p=0.000 n=20+20) Hash1K-48 377MB/s ± 6% 587MB/s ± 6% +55.76% (p=0.000 n=19+20) Hash8K-48 413MB/s ± 7% 709MB/s ± 6% +71.85% (p=0.000 n=20+19) Change-Id: I2963cf744eeb2e8191d4e4223fbf6f533a7fd405 Reviewed-on: https://go-review.googlesource.com/22607 Run-TryBot: Ilya Tocar Reviewed-by: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/crypto/sha1/sha1_test.go | 5 + src/crypto/sha1/sha1block_amd64.go | 23 + src/crypto/sha1/sha1block_amd64.s | 1301 +++++++++++++++++++++++++++- src/crypto/sha1/sha1block_decl.go | 2 +- 4 files changed, 1329 insertions(+), 2 deletions(-) create mode 100644 src/crypto/sha1/sha1block_amd64.go diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go index 9202e682a8f9b9..daab2aeaefb977 100644 --- a/src/crypto/sha1/sha1_test.go +++ b/src/crypto/sha1/sha1_test.go @@ -19,6 +19,7 @@ type sha1Test struct { } var golden = []sha1Test{ + {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"}, {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"}, @@ -120,6 +121,10 @@ func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8) } +func BenchmarkHash320Bytes(b *testing.B) { + benchmarkSize(b, 320) +} + func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024) } diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go new file mode 100644 index 00000000000000..84f8a520197db2 --- /dev/null +++ b/src/crypto/sha1/sha1block_amd64.go @@ -0,0 +1,23 @@ +// 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 sha1 + +//go:noescape + +func blockAVX2(dig *digest, p []byte) + +//go:noescape +func blockAMD64(dig *digest, p []byte) +func checkAVX2() bool + +var hasAVX2 = checkAVX2() + +func block(dig *digest, p []byte) { + if hasAVX2 && len(p) >= 256 { + blockAVX2(dig, p) + } else { + blockAMD64(dig, p) + } +} diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s index a504e147512c73..0cdb43b422fdcc 100644 --- a/src/crypto/sha1/sha1block_amd64.s +++ b/src/crypto/sha1/sha1block_amd64.s @@ -2,6 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// AVX2 version by Intel, same algorithm as code in Linux kernel: +// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha1_avx2_x86_64_asm.S +// Authors: +// Ilya Albrekht +// Maxim Locktyukhin +// Ronen Zohar +// Chandramouli Narayanan + + #include "textflag.h" // SHA1 block routine. See sha1block.go for Go equivalent. @@ -87,7 +96,7 @@ FUNC4(a, b, c, d, e); \ MIX(a, b, c, d, e, 0xCA62C1D6) -TEXT ·block(SB),NOSPLIT,$64-32 +TEXT ·blockAMD64(SB),NOSPLIT,$64-32 MOVQ dig+0(FP), BP MOVQ p_base+8(FP), SI MOVQ p_len+16(FP), DX @@ -214,3 +223,1293 @@ end: MOVL DX, (3*4)(DI) MOVL BP, (4*4)(DI) RET + + +// This is the implementation using AVX2. It is based on: +// "SHA-1 implementation with Intel(R) AVX2 instruction set extensions" +// From http://software.intel.com/en-us/articles +// (look for improving-the-performance-of-the-secure-hash-algorithm-1) +// This implementation is 2x unrolled, and interleaves vector instructions, +// used to precompute W, with scalar computation of current round +// for optimal scheduling. + +// Trivial helper macros. +#define UPDATE_HASH(A,TB,C,D,E) \ + ADDL (R9), A \ + MOVL A, (R9) \ + ADDL 4(R9), TB \ + MOVL TB, 4(R9) \ + ADDL 8(R9), C \ + MOVL C, 8(R9) \ + ADDL 12(R9), D \ + MOVL D, 12(R9) \ + ADDL 16(R9), E \ + MOVL E, 16(R9) + + + +// Helper macros for PRECALC, which does precomputations +#define PRECALC_0(OFFSET) \ + VMOVDQU OFFSET(R10),X0 + +#define PRECALC_1(OFFSET) \ + VINSERTI128 $1, OFFSET(R13), Y0, Y0 + +#define PRECALC_2(YREG) \ + VPSHUFB Y10, Y0, YREG + +#define PRECALC_4(YREG,K_OFFSET) \ + VPADDD K_OFFSET(R8), YREG, Y0 + +#define PRECALC_7(OFFSET) \ + VMOVDQU Y0, (OFFSET*2)(R14) + + +// Message scheduling pre-compute for rounds 0-15 +// R13 is a pointer to even 64-byte block +// R10 is a pointer to odd 64-byte block +// R14 is a pointer to temp buffer +// X0 is used as temp register +// YREG is clobbered as part of computation +// OFFSET chooses 16 byte chunk within a block +// R8 is a pointer to constants block +// K_OFFSET chooses K constants relevant to this round +// X10 holds swap mask +#define PRECALC_00_15(OFFSET,YREG) \ + PRECALC_0(OFFSET) \ + PRECALC_1(OFFSET) \ + PRECALC_2(YREG) \ + PRECALC_4(YREG,0x0) \ + PRECALC_7(OFFSET) + + +// Helper macros for PRECALC_16_31 +#define PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \ + VPALIGNR $8, REG_SUB_16, REG_SUB_12, REG \ // w[i-14] + VPSRLDQ $4, REG_SUB_4, Y0 // w[i-3] + +#define PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \ + VPXOR REG_SUB_8, REG, REG \ + VPXOR REG_SUB_16, Y0, Y0 + +#define PRECALC_18(REG) \ + VPXOR Y0, REG, REG \ + VPSLLDQ $12, REG, Y9 + +#define PRECALC_19(REG) \ + VPSLLD $1, REG, Y0 \ + VPSRLD $31, REG, REG + +#define PRECALC_20(REG) \ + VPOR REG, Y0, Y0 \ + VPSLLD $2, Y9, REG + +#define PRECALC_21(REG) \ + VPSRLD $30, Y9, Y9 \ + VPXOR REG, Y0, Y0 + +#define PRECALC_23(REG,K_OFFSET,OFFSET) \ + VPXOR Y9, Y0, REG \ + VPADDD K_OFFSET(R8), REG, Y0 \ + VMOVDQU Y0, (OFFSET)(R14) + +// Message scheduling pre-compute for rounds 16-31 +// calculating last 32 w[i] values in 8 XMM registers +// pre-calculate K+w[i] values and store to mem +// for later load by ALU add instruction. +// "brute force" vectorization for rounds 16-31 only +// due to w[i]->w[i-3] dependency. +// clobbers 5 input ymm registers REG_SUB* +// uses X0 and X9 as temp registers +// As always, R8 is a pointer to constants block +// and R14 is a pointer to temp buffer +#define PRECALC_16_31(REG,REG_SUB_4,REG_SUB_8,REG_SUB_12,REG_SUB_16,K_OFFSET,OFFSET) \ + PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \ + PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \ + PRECALC_18(REG) \ + PRECALC_19(REG) \ + PRECALC_20(REG) \ + PRECALC_21(REG) \ + PRECALC_23(REG,K_OFFSET,OFFSET) + + +// Helper macros for PRECALC_32_79 +#define PRECALC_32(REG_SUB_8,REG_SUB_4) \ + VPALIGNR $8, REG_SUB_8, REG_SUB_4, Y0 + +#define PRECALC_33(REG_SUB_28,REG) \ + VPXOR REG_SUB_28, REG, REG + +#define PRECALC_34(REG_SUB_16) \ + VPXOR REG_SUB_16, Y0, Y0 + +#define PRECALC_35(REG) \ + VPXOR Y0, REG, REG + +#define PRECALC_36(REG) \ + VPSLLD $2, REG, Y0 + +#define PRECALC_37(REG) \ + VPSRLD $30, REG, REG \ + VPOR REG, Y0, REG + +#define PRECALC_39(REG,K_OFFSET,OFFSET) \ + VPADDD K_OFFSET(R8), REG, Y0 \ + VMOVDQU Y0, (OFFSET)(R14) + +// Message scheduling pre-compute for rounds 32-79 +// In SHA-1 specification we have: +// w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) rol 1 +// Which is the same as: +// w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]) rol 2 +// This allows for more efficient vectorization, +// since w[i]->w[i-3] dependency is broken +#define PRECALC_32_79(REG,REG_SUB_4,REG_SUB_8,REG_SUB_16,REG_SUB_28,K_OFFSET,OFFSET) \ + PRECALC_32(REG_SUB_8,REG_SUB_4) \ + PRECALC_33(REG_SUB_28,REG) \ + PRECALC_34(REG_SUB_16) \ + PRECALC_35(REG) \ + PRECALC_36(REG) \ + PRECALC_37(REG) \ + PRECALC_39(REG,K_OFFSET,OFFSET) + +#define PRECALC \ + PRECALC_00_15(0,Y15) \ + PRECALC_00_15(0x10,Y14) \ + PRECALC_00_15(0x20,Y13) \ + PRECALC_00_15(0x30,Y12) \ + PRECALC_16_31(Y8,Y12,Y13,Y14,Y15,0,0x80) \ + PRECALC_16_31(Y7,Y8,Y12,Y13,Y14,0x20,0xa0) \ + PRECALC_16_31(Y5,Y7,Y8,Y12,Y13,0x20,0xc0) \ + PRECALC_16_31(Y3,Y5,Y7,Y8,Y12,0x20,0xe0) \ + PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x20,0x100) \ + PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x20,0x120) \ + PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x40,0x140) \ + PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x40,0x160) \ + PRECALC_32_79(Y8,Y12,Y13,Y15,Y7,0x40,0x180) \ + PRECALC_32_79(Y7,Y8,Y12,Y14,Y5,0x40,0x1a0) \ + PRECALC_32_79(Y5,Y7,Y8,Y13,Y3,0x40,0x1c0) \ + PRECALC_32_79(Y3,Y5,Y7,Y12,Y15,0x60,0x1e0) \ + PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x60,0x200) \ + PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x60,0x220) \ + PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \ + PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260) + +// Macros calculating individual rounds have general forn +// CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST +// CALC_ROUND_{PRE,POST} macros follow + +#define CALC_F1_PRE(OFFSET,REG_A,REG_B,REG_C,REG_E) \ + ADDL OFFSET(R15),REG_E \ + ANDNL REG_C,REG_A,BP \ + LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round + RORXL $0x1b, REG_A, R12 \ + RORXL $2, REG_A, REG_B // for next round + +// Calculate F for the next round +#define CALC_F1_POST(REG_A,REG_B,REG_E) \ + ANDL REG_B,REG_A \ // b&c + XORL BP, REG_A \ // F1 = (b&c) ^ (~b&d) + LEAL (REG_E)(R12*1), REG_E // E += A >>> 5 + + +// Registers are cycleickly rotated DX -> AX -> DI -> SI -> BX -> CX +#define CALC_0 \ + MOVL SI, BX \ // Precalculating first round + RORXL $2, SI, SI \ + ANDNL AX, BX, BP \ + ANDL DI, BX \ + XORL BP, BX \ + CALC_F1_PRE(0x0,CX,BX,DI,DX) \ + PRECALC_0(0x80) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_1 \ + CALC_F1_PRE(0x4,DX,CX,SI,AX) \ + PRECALC_1(0x80) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_2 \ + CALC_F1_PRE(0x8,AX,DX,BX,DI) \ + PRECALC_2(Y15) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_3 \ + CALC_F1_PRE(0xc,DI,AX,CX,SI) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_4 \ + CALC_F1_PRE(0x20,SI,DI,DX,BX) \ + PRECALC_4(Y15,0x0) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_5 \ + CALC_F1_PRE(0x24,BX,SI,AX,CX) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_6 \ + CALC_F1_PRE(0x28,CX,BX,DI,DX) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_7 \ + CALC_F1_PRE(0x2c,DX,CX,SI,AX) \ + PRECALC_7(0x0) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_8 \ + CALC_F1_PRE(0x40,AX,DX,BX,DI) \ + PRECALC_0(0x90) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_9 \ + CALC_F1_PRE(0x44,DI,AX,CX,SI) \ + PRECALC_1(0x90) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_10 \ + CALC_F1_PRE(0x48,SI,DI,DX,BX) \ + PRECALC_2(Y14) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_11 \ + CALC_F1_PRE(0x4c,BX,SI,AX,CX) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_12 \ + CALC_F1_PRE(0x60,CX,BX,DI,DX) \ + PRECALC_4(Y14,0x0) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_13 \ + CALC_F1_PRE(0x64,DX,CX,SI,AX) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_14 \ + CALC_F1_PRE(0x68,AX,DX,BX,DI) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_15 \ + CALC_F1_PRE(0x6c,DI,AX,CX,SI) \ + PRECALC_7(0x10) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_16 \ + CALC_F1_PRE(0x80,SI,DI,DX,BX) \ + PRECALC_0(0xa0) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_17 \ + CALC_F1_PRE(0x84,BX,SI,AX,CX) \ + PRECALC_1(0xa0) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_18 \ + CALC_F1_PRE(0x88,CX,BX,DI,DX) \ + PRECALC_2(Y13) \ + CALC_F1_POST(CX,SI,DX) + + +#define CALC_F2_PRE(OFFSET,REG_A,REG_B,REG_E) \ + ADDL OFFSET(R15),REG_E \ + LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round + RORXL $0x1b, REG_A, R12 \ + RORXL $2, REG_A, REG_B // for next round + +#define CALC_F2_POST(REG_A,REG_B,REG_C,REG_E) \ + XORL REG_B, REG_A \ + ADDL R12, REG_E \ + XORL REG_C, REG_A + +#define CALC_19 \ + CALC_F2_PRE(0x8c,DX,CX,AX) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_20 \ + CALC_F2_PRE(0xa0,AX,DX,DI) \ + PRECALC_4(Y13,0x0) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_21 \ + CALC_F2_PRE(0xa4,DI,AX,SI) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_22 \ + CALC_F2_PRE(0xa8,SI,DI,BX) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_23 \ + CALC_F2_PRE(0xac,BX,SI,CX) \ + PRECALC_7(0x20) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_24 \ + CALC_F2_PRE(0xc0,CX,BX,DX) \ + PRECALC_0(0xb0) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_25 \ + CALC_F2_PRE(0xc4,DX,CX,AX) \ + PRECALC_1(0xb0) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_26 \ + CALC_F2_PRE(0xc8,AX,DX,DI) \ + PRECALC_2(Y12) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_27 \ + CALC_F2_PRE(0xcc,DI,AX,SI) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_28 \ + CALC_F2_PRE(0xe0,SI,DI,BX) \ + PRECALC_4(Y12,0x0) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_29 \ + CALC_F2_PRE(0xe4,BX,SI,CX) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_30 \ + CALC_F2_PRE(0xe8,CX,BX,DX) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_31 \ + CALC_F2_PRE(0xec,DX,CX,AX) \ + PRECALC_7(0x30) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_32 \ + CALC_F2_PRE(0x100,AX,DX,DI) \ + PRECALC_16(Y15,Y14,Y12,Y8) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_33 \ + CALC_F2_PRE(0x104,DI,AX,SI) \ + PRECALC_17(Y15,Y13,Y8) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_34 \ + CALC_F2_PRE(0x108,SI,DI,BX) \ + PRECALC_18(Y8) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_35 \ + CALC_F2_PRE(0x10c,BX,SI,CX) \ + PRECALC_19(Y8) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_36 \ + CALC_F2_PRE(0x120,CX,BX,DX) \ + PRECALC_20(Y8) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_37 \ + CALC_F2_PRE(0x124,DX,CX,AX) \ + PRECALC_21(Y8) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_38 \ + CALC_F2_PRE(0x128,AX,DX,DI) \ + CALC_F2_POST(AX,CX,BX,DI) + + +#define CALC_F3_PRE(OFFSET,REG_E) \ + ADDL OFFSET(R15),REG_E + +#define CALC_F3_POST(REG_A,REG_B,REG_C,REG_E,REG_TB) \ + LEAL (REG_E)(REG_TB*1), REG_E \ // Add F from the previous round + MOVL REG_B, BP \ + ORL REG_A, BP \ + RORXL $0x1b, REG_A, R12 \ + RORXL $2, REG_A, REG_TB \ + ANDL REG_C, BP \ // Calculate F for the next round + ANDL REG_B, REG_A \ + ORL BP, REG_A \ + ADDL R12, REG_E + +#define CALC_39 \ + CALC_F3_PRE(0x12c,SI) \ + PRECALC_23(Y8,0x0,0x80) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_40 \ + CALC_F3_PRE(0x140,BX) \ + PRECALC_16(Y14,Y13,Y8,Y7) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_41 \ + CALC_F3_PRE(0x144,CX) \ + PRECALC_17(Y14,Y12,Y7) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_42 \ + CALC_F3_PRE(0x148,DX) \ + PRECALC_18(Y7) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_43 \ + CALC_F3_PRE(0x14c,AX) \ + PRECALC_19(Y7) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_44 \ + CALC_F3_PRE(0x160,DI) \ + PRECALC_20(Y7) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_45 \ + CALC_F3_PRE(0x164,SI) \ + PRECALC_21(Y7) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_46 \ + CALC_F3_PRE(0x168,BX) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_47 \ + CALC_F3_PRE(0x16c,CX) \ + VPXOR Y9, Y0, Y7 \ + VPADDD 0x20(R8), Y7, Y0 \ + VMOVDQU Y0, 0xa0(R14) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_48 \ + CALC_F3_PRE(0x180,DX) \ + PRECALC_16(Y13,Y12,Y7,Y5) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_49 \ + CALC_F3_PRE(0x184,AX) \ + PRECALC_17(Y13,Y8,Y5) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_50 \ + CALC_F3_PRE(0x188,DI) \ + PRECALC_18(Y5) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_51 \ + CALC_F3_PRE(0x18c,SI) \ + PRECALC_19(Y5) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_52 \ + CALC_F3_PRE(0x1a0,BX) \ + PRECALC_20(Y5) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_53 \ + CALC_F3_PRE(0x1a4,CX) \ + PRECALC_21(Y5) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_54 \ + CALC_F3_PRE(0x1a8,DX) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_55 \ + CALC_F3_PRE(0x1ac,AX) \ + PRECALC_23(Y5,0x20,0xc0) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_56 \ + CALC_F3_PRE(0x1c0,DI) \ + PRECALC_16(Y12,Y8,Y5,Y3) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_57 \ + CALC_F3_PRE(0x1c4,SI) \ + PRECALC_17(Y12,Y7,Y3) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_58 \ + CALC_F3_PRE(0x1c8,BX) \ + PRECALC_18(Y3) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_59 \ + CALC_F2_PRE(0x1cc,BX,SI,CX) \ + PRECALC_19(Y3) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_60 \ + CALC_F2_PRE(0x1e0,CX,BX,DX) \ + PRECALC_20(Y3) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_61 \ + CALC_F2_PRE(0x1e4,DX,CX,AX) \ + PRECALC_21(Y3) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_62 \ + CALC_F2_PRE(0x1e8,AX,DX,DI) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_63 \ + CALC_F2_PRE(0x1ec,DI,AX,SI) \ + PRECALC_23(Y3,0x20,0xe0) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_64 \ + CALC_F2_PRE(0x200,SI,DI,BX) \ + PRECALC_32(Y5,Y3) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_65 \ + CALC_F2_PRE(0x204,BX,SI,CX) \ + PRECALC_33(Y14,Y15) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_66 \ + CALC_F2_PRE(0x208,CX,BX,DX) \ + PRECALC_34(Y8) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_67 \ + CALC_F2_PRE(0x20c,DX,CX,AX) \ + PRECALC_35(Y15) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_68 \ + CALC_F2_PRE(0x220,AX,DX,DI) \ + PRECALC_36(Y15) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_69 \ + CALC_F2_PRE(0x224,DI,AX,SI) \ + PRECALC_37(Y15) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_70 \ + CALC_F2_PRE(0x228,SI,DI,BX) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_71 \ + CALC_F2_PRE(0x22c,BX,SI,CX) \ + PRECALC_39(Y15,0x20,0x100) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_72 \ + CALC_F2_PRE(0x240,CX,BX,DX) \ + PRECALC_32(Y3,Y15) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_73 \ + CALC_F2_PRE(0x244,DX,CX,AX) \ + PRECALC_33(Y13,Y14) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_74 \ + CALC_F2_PRE(0x248,AX,DX,DI) \ + PRECALC_34(Y7) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_75 \ + CALC_F2_PRE(0x24c,DI,AX,SI) \ + PRECALC_35(Y14) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_76 \ + CALC_F2_PRE(0x260,SI,DI,BX) \ + PRECALC_36(Y14) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_77 \ + CALC_F2_PRE(0x264,BX,SI,CX) \ + PRECALC_37(Y14) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_78 \ + CALC_F2_PRE(0x268,CX,BX,DX) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_79 \ + ADDL 0x26c(R15), AX \ + LEAL (AX)(CX*1), AX \ + RORXL $0x1b, DX, R12 \ + PRECALC_39(Y14,0x20,0x120) \ + ADDL R12, AX + +// Similar to CALC_0 +#define CALC_80 \ + MOVL CX, DX \ + RORXL $2, CX, CX \ + ANDNL SI, DX, BP \ + ANDL BX, DX \ + XORL BP, DX \ + CALC_F1_PRE(0x10,AX,DX,BX,DI) \ + PRECALC_32(Y15,Y14) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_81 \ + CALC_F1_PRE(0x14,DI,AX,CX,SI) \ + PRECALC_33(Y12,Y13) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_82 \ + CALC_F1_PRE(0x18,SI,DI,DX,BX) \ + PRECALC_34(Y5) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_83 \ + CALC_F1_PRE(0x1c,BX,SI,AX,CX) \ + PRECALC_35(Y13) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_84 \ + CALC_F1_PRE(0x30,CX,BX,DI,DX) \ + PRECALC_36(Y13) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_85 \ + CALC_F1_PRE(0x34,DX,CX,SI,AX) \ + PRECALC_37(Y13) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_86 \ + CALC_F1_PRE(0x38,AX,DX,BX,DI) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_87 \ + CALC_F1_PRE(0x3c,DI,AX,CX,SI) \ + PRECALC_39(Y13,0x40,0x140) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_88 \ + CALC_F1_PRE(0x50,SI,DI,DX,BX) \ + PRECALC_32(Y14,Y13) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_89 \ + CALC_F1_PRE(0x54,BX,SI,AX,CX) \ + PRECALC_33(Y8,Y12) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_90 \ + CALC_F1_PRE(0x58,CX,BX,DI,DX) \ + PRECALC_34(Y3) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_91 \ + CALC_F1_PRE(0x5c,DX,CX,SI,AX) \ + PRECALC_35(Y12) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_92 \ + CALC_F1_PRE(0x70,AX,DX,BX,DI) \ + PRECALC_36(Y12) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_93 \ + CALC_F1_PRE(0x74,DI,AX,CX,SI) \ + PRECALC_37(Y12) \ + CALC_F1_POST(DI,DX,SI) + +#define CALC_94 \ + CALC_F1_PRE(0x78,SI,DI,DX,BX) \ + CALC_F1_POST(SI,AX,BX) + +#define CALC_95 \ + CALC_F1_PRE(0x7c,BX,SI,AX,CX) \ + PRECALC_39(Y12,0x40,0x160) \ + CALC_F1_POST(BX,DI,CX) + +#define CALC_96 \ + CALC_F1_PRE(0x90,CX,BX,DI,DX) \ + PRECALC_32(Y13,Y12) \ + CALC_F1_POST(CX,SI,DX) + +#define CALC_97 \ + CALC_F1_PRE(0x94,DX,CX,SI,AX) \ + PRECALC_33(Y7,Y8) \ + CALC_F1_POST(DX,BX,AX) + +#define CALC_98 \ + CALC_F1_PRE(0x98,AX,DX,BX,DI) \ + PRECALC_34(Y15) \ + CALC_F1_POST(AX,CX,DI) + +#define CALC_99 \ + CALC_F2_PRE(0x9c,DI,AX,SI) \ + PRECALC_35(Y8) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_100 \ + CALC_F2_PRE(0xb0,SI,DI,BX) \ + PRECALC_36(Y8) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_101 \ + CALC_F2_PRE(0xb4,BX,SI,CX) \ + PRECALC_37(Y8) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_102 \ + CALC_F2_PRE(0xb8,CX,BX,DX) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_103 \ + CALC_F2_PRE(0xbc,DX,CX,AX) \ + PRECALC_39(Y8,0x40,0x180) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_104 \ + CALC_F2_PRE(0xd0,AX,DX,DI) \ + PRECALC_32(Y12,Y8) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_105 \ + CALC_F2_PRE(0xd4,DI,AX,SI) \ + PRECALC_33(Y5,Y7) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_106 \ + CALC_F2_PRE(0xd8,SI,DI,BX) \ + PRECALC_34(Y14) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_107 \ + CALC_F2_PRE(0xdc,BX,SI,CX) \ + PRECALC_35(Y7) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_108 \ + CALC_F2_PRE(0xf0,CX,BX,DX) \ + PRECALC_36(Y7) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_109 \ + CALC_F2_PRE(0xf4,DX,CX,AX) \ + PRECALC_37(Y7) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_110 \ + CALC_F2_PRE(0xf8,AX,DX,DI) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_111 \ + CALC_F2_PRE(0xfc,DI,AX,SI) \ + PRECALC_39(Y7,0x40,0x1a0) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_112 \ + CALC_F2_PRE(0x110,SI,DI,BX) \ + PRECALC_32(Y8,Y7) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_113 \ + CALC_F2_PRE(0x114,BX,SI,CX) \ + PRECALC_33(Y3,Y5) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_114 \ + CALC_F2_PRE(0x118,CX,BX,DX) \ + PRECALC_34(Y13) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_115 \ + CALC_F2_PRE(0x11c,DX,CX,AX) \ + PRECALC_35(Y5) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_116 \ + CALC_F2_PRE(0x130,AX,DX,DI) \ + PRECALC_36(Y5) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_117 \ + CALC_F2_PRE(0x134,DI,AX,SI) \ + PRECALC_37(Y5) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_118 \ + CALC_F2_PRE(0x138,SI,DI,BX) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_119 \ + CALC_F3_PRE(0x13c,CX) \ + PRECALC_39(Y5,0x40,0x1c0) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_120 \ + CALC_F3_PRE(0x150,DX) \ + PRECALC_32(Y7,Y5) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_121 \ + CALC_F3_PRE(0x154,AX) \ + PRECALC_33(Y15,Y3) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_122 \ + CALC_F3_PRE(0x158,DI) \ + PRECALC_34(Y12) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_123 \ + CALC_F3_PRE(0x15c,SI) \ + PRECALC_35(Y3) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_124 \ + CALC_F3_PRE(0x170,BX) \ + PRECALC_36(Y3) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_125 \ + CALC_F3_PRE(0x174,CX) \ + PRECALC_37(Y3) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_126 \ + CALC_F3_PRE(0x178,DX) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_127 \ + CALC_F3_PRE(0x17c,AX) \ + PRECALC_39(Y3,0x60,0x1e0) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_128 \ + CALC_F3_PRE(0x190,DI) \ + PRECALC_32(Y5,Y3) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_129 \ + CALC_F3_PRE(0x194,SI) \ + PRECALC_33(Y14,Y15) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_130 \ + CALC_F3_PRE(0x198,BX) \ + PRECALC_34(Y8) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_131 \ + CALC_F3_PRE(0x19c,CX) \ + PRECALC_35(Y15) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_132 \ + CALC_F3_PRE(0x1b0,DX) \ + PRECALC_36(Y15) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_133 \ + CALC_F3_PRE(0x1b4,AX) \ + PRECALC_37(Y15) \ + CALC_F3_POST(DX,BX,SI,AX,CX) + +#define CALC_134 \ + CALC_F3_PRE(0x1b8,DI) \ + CALC_F3_POST(AX,CX,BX,DI,DX) + +#define CALC_135 \ + CALC_F3_PRE(0x1bc,SI) \ + PRECALC_39(Y15,0x60,0x200) \ + CALC_F3_POST(DI,DX,CX,SI,AX) + +#define CALC_136 \ + CALC_F3_PRE(0x1d0,BX) \ + PRECALC_32(Y3,Y15) \ + CALC_F3_POST(SI,AX,DX,BX,DI) + +#define CALC_137 \ + CALC_F3_PRE(0x1d4,CX) \ + PRECALC_33(Y13,Y14) \ + CALC_F3_POST(BX,DI,AX,CX,SI) + +#define CALC_138 \ + CALC_F3_PRE(0x1d8,DX) \ + PRECALC_34(Y7) \ + CALC_F3_POST(CX,SI,DI,DX,BX) + +#define CALC_139 \ + CALC_F2_PRE(0x1dc,DX,CX,AX) \ + PRECALC_35(Y14) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_140 \ + CALC_F2_PRE(0x1f0,AX,DX,DI) \ + PRECALC_36(Y14) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_141 \ + CALC_F2_PRE(0x1f4,DI,AX,SI) \ + PRECALC_37(Y14) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_142 \ + CALC_F2_PRE(0x1f8,SI,DI,BX) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_143 \ + CALC_F2_PRE(0x1fc,BX,SI,CX) \ + PRECALC_39(Y14,0x60,0x220) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_144 \ + CALC_F2_PRE(0x210,CX,BX,DX) \ + PRECALC_32(Y15,Y14) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_145 \ + CALC_F2_PRE(0x214,DX,CX,AX) \ + PRECALC_33(Y12,Y13) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_146 \ + CALC_F2_PRE(0x218,AX,DX,DI) \ + PRECALC_34(Y5) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_147 \ + CALC_F2_PRE(0x21c,DI,AX,SI) \ + PRECALC_35(Y13) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_148 \ + CALC_F2_PRE(0x230,SI,DI,BX) \ + PRECALC_36(Y13) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_149 \ + CALC_F2_PRE(0x234,BX,SI,CX) \ + PRECALC_37(Y13) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_150 \ + CALC_F2_PRE(0x238,CX,BX,DX) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_151 \ + CALC_F2_PRE(0x23c,DX,CX,AX) \ + PRECALC_39(Y13,0x60,0x240) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_152 \ + CALC_F2_PRE(0x250,AX,DX,DI) \ + PRECALC_32(Y14,Y13) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_153 \ + CALC_F2_PRE(0x254,DI,AX,SI) \ + PRECALC_33(Y8,Y12) \ + CALC_F2_POST(DI,DX,CX,SI) + +#define CALC_154 \ + CALC_F2_PRE(0x258,SI,DI,BX) \ + PRECALC_34(Y3) \ + CALC_F2_POST(SI,AX,DX,BX) + +#define CALC_155 \ + CALC_F2_PRE(0x25c,BX,SI,CX) \ + PRECALC_35(Y12) \ + CALC_F2_POST(BX,DI,AX,CX) + +#define CALC_156 \ + CALC_F2_PRE(0x270,CX,BX,DX) \ + PRECALC_36(Y12) \ + CALC_F2_POST(CX,SI,DI,DX) + +#define CALC_157 \ + CALC_F2_PRE(0x274,DX,CX,AX) \ + PRECALC_37(Y12) \ + CALC_F2_POST(DX,BX,SI,AX) + +#define CALC_158 \ + CALC_F2_PRE(0x278,AX,DX,DI) \ + CALC_F2_POST(AX,CX,BX,DI) + +#define CALC_159 \ + ADDL 0x27c(R15),SI \ + LEAL (SI)(AX*1), SI \ + RORXL $0x1b, DI, R12 \ + PRECALC_39(Y12,0x60,0x260) \ + ADDL R12, SI + + + +#define CALC \ + MOVL (R9), CX \ + MOVL 4(R9), SI \ + MOVL 8(R9), DI \ + MOVL 12(R9), AX \ + MOVL 16(R9), DX \ + MOVQ SP, R14 \ + LEAQ (2*4*80+32)(SP), R15 \ + PRECALC \ // Precalc WK for first 2 blocks + XCHGQ R15, R14 \ +loop: \ // this loops is unrolled + CMPQ R10, R8 \ // we use R8 value (set below) as a signal of a last block + JNE begin \ + VZEROUPPER \ + RET \ +begin: \ + CALC_0 \ + CALC_1 \ + CALC_2 \ + CALC_3 \ + CALC_4 \ + CALC_5 \ + CALC_6 \ + CALC_7 \ + CALC_8 \ + CALC_9 \ + CALC_10 \ + CALC_11 \ + CALC_12 \ + CALC_13 \ + CALC_14 \ + CALC_15 \ + CALC_16 \ + CALC_17 \ + CALC_18 \ + CALC_19 \ + CALC_20 \ + CALC_21 \ + CALC_22 \ + CALC_23 \ + CALC_24 \ + CALC_25 \ + CALC_26 \ + CALC_27 \ + CALC_28 \ + CALC_29 \ + CALC_30 \ + CALC_31 \ + CALC_32 \ + CALC_33 \ + CALC_34 \ + CALC_35 \ + CALC_36 \ + CALC_37 \ + CALC_38 \ + CALC_39 \ + CALC_40 \ + CALC_41 \ + CALC_42 \ + CALC_43 \ + CALC_44 \ + CALC_45 \ + CALC_46 \ + CALC_47 \ + CALC_48 \ + CALC_49 \ + CALC_50 \ + CALC_51 \ + CALC_52 \ + CALC_53 \ + CALC_54 \ + CALC_55 \ + CALC_56 \ + CALC_57 \ + CALC_58 \ + CALC_59 \ + ADDQ $128, R10 \ // move to next even-64-byte block + CMPQ R10, R11 \ // is current block the last one? + CMOVQCC R8, R10 \ // signal the last iteration smartly + CALC_60 \ + CALC_61 \ + CALC_62 \ + CALC_63 \ + CALC_64 \ + CALC_65 \ + CALC_66 \ + CALC_67 \ + CALC_68 \ + CALC_69 \ + CALC_70 \ + CALC_71 \ + CALC_72 \ + CALC_73 \ + CALC_74 \ + CALC_75 \ + CALC_76 \ + CALC_77 \ + CALC_78 \ + CALC_79 \ + UPDATE_HASH(AX,DX,BX,SI,DI) \ + CMPQ R10, R8 \ // is current block the last one? + JE loop\ + MOVL DX, CX \ + CALC_80 \ + CALC_81 \ + CALC_82 \ + CALC_83 \ + CALC_84 \ + CALC_85 \ + CALC_86 \ + CALC_87 \ + CALC_88 \ + CALC_89 \ + CALC_90 \ + CALC_91 \ + CALC_92 \ + CALC_93 \ + CALC_94 \ + CALC_95 \ + CALC_96 \ + CALC_97 \ + CALC_98 \ + CALC_99 \ + CALC_100 \ + CALC_101 \ + CALC_102 \ + CALC_103 \ + CALC_104 \ + CALC_105 \ + CALC_106 \ + CALC_107 \ + CALC_108 \ + CALC_109 \ + CALC_110 \ + CALC_111 \ + CALC_112 \ + CALC_113 \ + CALC_114 \ + CALC_115 \ + CALC_116 \ + CALC_117 \ + CALC_118 \ + CALC_119 \ + CALC_120 \ + CALC_121 \ + CALC_122 \ + CALC_123 \ + CALC_124 \ + CALC_125 \ + CALC_126 \ + CALC_127 \ + CALC_128 \ + CALC_129 \ + CALC_130 \ + CALC_131 \ + CALC_132 \ + CALC_133 \ + CALC_134 \ + CALC_135 \ + CALC_136 \ + CALC_137 \ + CALC_138 \ + CALC_139 \ + ADDQ $128, R13 \ //move to next even-64-byte block + CMPQ R13, R11 \ //is current block the last one? + CMOVQCC R8, R10 \ + CALC_140 \ + CALC_141 \ + CALC_142 \ + CALC_143 \ + CALC_144 \ + CALC_145 \ + CALC_146 \ + CALC_147 \ + CALC_148 \ + CALC_149 \ + CALC_150 \ + CALC_151 \ + CALC_152 \ + CALC_153 \ + CALC_154 \ + CALC_155 \ + CALC_156 \ + CALC_157 \ + CALC_158 \ + CALC_159 \ + UPDATE_HASH(SI,DI,DX,CX,BX) \ + MOVL SI, R12 \ //Reset state for AVX2 reg permutation + MOVL DI, SI \ + MOVL DX, DI \ + MOVL BX, DX \ + MOVL CX, AX \ + MOVL R12, CX \ + XCHGQ R15, R14 \ + JMP loop + + + +TEXT ·blockAVX2(SB),$1408-32 + + MOVQ dig+0(FP), DI + MOVQ p_base+8(FP), SI + MOVQ p_len+16(FP), DX + SHRQ $6, DX + SHLQ $6, DX + + MOVQ $K_XMM_AR<>(SB), R8 + + MOVQ DI, R9 + MOVQ SI, R10 + LEAQ 64(SI), R13 + + ADDQ SI, DX + ADDQ $64, DX + MOVQ DX, R11 + + CMPQ R13, R11 + CMOVQCC R8, R13 + + MOVQ $BSWAP_SHUFB_CTL<>(SB), R8 + VMOVDQU (R8), Y10 + MOVQ $K_XMM_AR<>(SB), R8 //restore R8 + + CALC // RET is inside macros + + +// func checkAVX2() bool +// returns whether AVX2 is supported +TEXT ·checkAVX2(SB),NOSPLIT,$0 + CMPB runtime·support_avx2(SB), $1 + JE has + MOVB $0, ret+0(FP) + RET +has: + MOVB $1, ret+0(FP) + RET + + +DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x04(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x08(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x0c(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x10(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x14(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x18(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x1c(SB)/4,$0x5a827999 +DATA K_XMM_AR<>+0x20(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x24(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x28(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x2c(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x30(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x34(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x38(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x3c(SB)/4,$0x6ed9eba1 +DATA K_XMM_AR<>+0x40(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x44(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x48(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x4c(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x50(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x54(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x58(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x5c(SB)/4,$0x8f1bbcdc +DATA K_XMM_AR<>+0x60(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x64(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x68(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x6c(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x70(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x74(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x78(SB)/4,$0xca62c1d6 +DATA K_XMM_AR<>+0x7c(SB)/4,$0xca62c1d6 +GLOBL K_XMM_AR<>(SB),RODATA,$128 + +DATA BSWAP_SHUFB_CTL<>+0x00(SB)/4,$0x00010203 +DATA BSWAP_SHUFB_CTL<>+0x04(SB)/4,$0x04050607 +DATA BSWAP_SHUFB_CTL<>+0x08(SB)/4,$0x08090a0b +DATA BSWAP_SHUFB_CTL<>+0x0c(SB)/4,$0x0c0d0e0f +DATA BSWAP_SHUFB_CTL<>+0x10(SB)/4,$0x00010203 +DATA BSWAP_SHUFB_CTL<>+0x14(SB)/4,$0x04050607 +DATA BSWAP_SHUFB_CTL<>+0x18(SB)/4,$0x08090a0b +DATA BSWAP_SHUFB_CTL<>+0x1c(SB)/4,$0x0c0d0e0f +GLOBL BSWAP_SHUFB_CTL<>(SB),RODATA,$32 diff --git a/src/crypto/sha1/sha1block_decl.go b/src/crypto/sha1/sha1block_decl.go index a85b74b8787174..6d2d073d137331 100644 --- a/src/crypto/sha1/sha1block_decl.go +++ b/src/crypto/sha1/sha1block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 amd64p32 arm 386 s390x +// +build amd64p32 arm 386 s390x package sha1 From bf151cc2aa4094b4633a7e5f07a34227d58231fe Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 5 May 2016 16:51:54 -0700 Subject: [PATCH 017/267] cmd/compile/internal/mips64: fix large uint -> float conversion Re-enable TestFP in cmd/compile/internal/gc on mips64. Fixes #15552. Change-Id: I5c3a5564b94d28c723358f0862468fb6da371991 Reviewed-on: https://go-review.googlesource.com/22835 Reviewed-by: Brad Fitzpatrick Reviewed-by: Minux Ma Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/ssa_test.go | 7 +------ src/cmd/compile/internal/mips64/gsubr.go | 11 +++++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go index 8a233eafe0d6d7..c89917df88c268 100644 --- a/src/cmd/compile/internal/gc/ssa_test.go +++ b/src/cmd/compile/internal/gc/ssa_test.go @@ -57,12 +57,7 @@ func TestArithmetic(t *testing.T) { } // TestFP tests that both backends have the same result for floating point expressions. -func TestFP(t *testing.T) { - if runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" { - t.Skip("legacy mips64 compiler doesn't handle uint->float conversion correctly (issue 15552)") - } - runTest(t, "fp_ssa.go") -} +func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") } // TestArithmeticBoundary tests boundary results for arithmetic operations. func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") } diff --git a/src/cmd/compile/internal/mips64/gsubr.go b/src/cmd/compile/internal/mips64/gsubr.go index 864fd76d121f9e..eb56d8b82e6e93 100644 --- a/src/cmd/compile/internal/mips64/gsubr.go +++ b/src/cmd/compile/internal/mips64/gsubr.go @@ -466,7 +466,7 @@ func gmove(f *gc.Node, t *gc.Node) { //return; // algorithm is: // if small enough, use native int64 -> float64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. + // otherwise, halve (x -> (x>>1)|(x&1)), convert, and double. /* * integer to float */ @@ -496,9 +496,16 @@ func gmove(f *gc.Node, t *gc.Node) { gmove(&bigi, &rtmp) gins(mips.AAND, &r1, &rtmp) p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0) - p2 := gins(mips.ASRLV, nil, &r1) + var r3 gc.Node + gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil) + p2 := gins3(mips.AAND, nil, &r1, &r3) p2.From.Type = obj.TYPE_CONST p2.From.Offset = 1 + p3 := gins(mips.ASRLV, nil, &r1) + p3.From.Type = obj.TYPE_CONST + p3.From.Offset = 1 + gins(mips.AOR, &r3, &r1) + gc.Regfree(&r3) gc.Patch(p1, gc.Pc) } From 2dc680007e35f4cb87527582eb73a653392aa8c3 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 08:26:37 -0700 Subject: [PATCH 018/267] runtime: merge the last four os-vs-os1 files together Change-Id: Ib0ba691c4657fe18a4659753e70d97c623cb9c1d Reviewed-on: https://go-review.googlesource.com/22850 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/os1_freebsd.go | 30 ++++++++ src/runtime/os1_nacl.go | 62 ++++++++++++++++ src/runtime/os1_openbsd.go | 33 +++++++++ src/runtime/os1_plan9.go | 143 ++++++++++++++++++++++++++++++++++++ src/runtime/os_freebsd.go | 32 -------- src/runtime/os_nacl.go | 64 ---------------- src/runtime/os_openbsd.go | 33 --------- src/runtime/os_plan9.go | 145 ------------------------------------- 8 files changed, 268 insertions(+), 274 deletions(-) diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go index 0dafe02325b792..3a73b6627743e3 100644 --- a/src/runtime/os1_freebsd.go +++ b/src/runtime/os1_freebsd.go @@ -9,6 +9,36 @@ import ( "unsafe" ) +type mOS struct{} + +//go:noescape +func thr_new(param *thrparam, size int32) + +//go:noescape +func sigaltstack(new, old *stackt) + +//go:noescape +func sigaction(sig int32, new, old *sigactiont) + +//go:noescape +func sigprocmask(how int32, new, old *sigset) + +//go:noescape +func setitimer(mode int32, new, old *itimerval) + +//go:noescape +func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 + +//go:noescape +func getrlimit(kind int32, limit unsafe.Pointer) int32 +func raise(sig int32) +func raiseproc(sig int32) + +//go:noescape +func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32 + +func osyield() + // From FreeBSD's const ( _CTL_HW = 6 diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go index feea4966529496..6cbd16de159c8c 100644 --- a/src/runtime/os1_nacl.go +++ b/src/runtime/os1_nacl.go @@ -6,6 +6,68 @@ package runtime import "unsafe" +type mOS struct { + waitsema int32 // semaphore for parking on locks + waitsemacount int32 + waitsemalock int32 +} + +func nacl_exception_stack(p uintptr, size int32) int32 +func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32 +func nacl_sem_create(flag int32) int32 +func nacl_sem_wait(sem int32) int32 +func nacl_sem_post(sem int32) int32 +func nacl_mutex_create(flag int32) int32 +func nacl_mutex_lock(mutex int32) int32 +func nacl_mutex_trylock(mutex int32) int32 +func nacl_mutex_unlock(mutex int32) int32 +func nacl_cond_create(flag int32) int32 +func nacl_cond_wait(cond, n int32) int32 +func nacl_cond_signal(cond int32) int32 +func nacl_cond_broadcast(cond int32) int32 + +//go:noescape +func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32 +func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32 + +//go:noescape +func nacl_nanosleep(ts, extra *timespec) int32 +func nanotime() int64 +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer +func exit(code int32) +func osyield() + +//go:noescape +func write(fd uintptr, p unsafe.Pointer, n int32) int32 + +//go:linkname os_sigpipe os.sigpipe +func os_sigpipe() { + throw("too many writes on closed pipe") +} + +func dieFromSignal(sig int32) { + exit(2) +} + +func sigpanic() { + g := getg() + if !canpanic(g) { + throw("unexpected signal during runtime execution") + } + + // Native Client only invokes the exception handler for memory faults. + g.sig = _SIGSEGV + panicmem() +} + +func raiseproc(sig int32) { +} + +// Stubs so tests can link correctly. These should never be called. +func open(name *byte, mode, perm int32) int32 +func closefd(fd int32) int32 +func read(fd int32, p unsafe.Pointer, n int32) int32 + type sigset struct{} // Called to initialize a new m (including the bootstrap m). diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go index 447dff81938e4a..ded6b1d4ea4a83 100644 --- a/src/runtime/os1_openbsd.go +++ b/src/runtime/os1_openbsd.go @@ -9,6 +9,39 @@ import ( "unsafe" ) +type mOS struct { + waitsemacount uint32 +} + +//go:noescape +func setitimer(mode int32, new, old *itimerval) + +//go:noescape +func sigaction(sig int32, new, old *sigactiont) + +//go:noescape +func sigaltstack(new, old *stackt) + +//go:noescape +func sigprocmask(mode int32, new sigset) sigset + +//go:noescape +func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 + +func raise(sig int32) +func raiseproc(sig int32) + +//go:noescape +func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32 + +//go:noescape +func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 + +//go:noescape +func thrwakeup(ident uintptr, n int32) int32 + +func osyield() + const ( _ESRCH = 3 _EAGAIN = 35 diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go index 6c7e36d0620a0f..2f3a0d1a19b2fd 100644 --- a/src/runtime/os1_plan9.go +++ b/src/runtime/os1_plan9.go @@ -9,6 +9,149 @@ import ( "unsafe" ) +type mOS struct { + waitsemacount uint32 + notesig *int8 + errstr *byte +} + +func closefd(fd int32) int32 + +//go:noescape +func open(name *byte, mode, perm int32) int32 + +//go:noescape +func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + +//go:noescape +func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + +func seek(fd int32, offset int64, whence int32) int64 + +//go:noescape +func exits(msg *byte) + +//go:noescape +func brk_(addr unsafe.Pointer) int32 + +func sleep(ms int32) int32 + +func rfork(flags int32) int32 + +//go:noescape +func plan9_semacquire(addr *uint32, block int32) int32 + +//go:noescape +func plan9_tsemacquire(addr *uint32, ms int32) int32 + +//go:noescape +func plan9_semrelease(addr *uint32, count int32) int32 + +//go:noescape +func notify(fn unsafe.Pointer) int32 + +func noted(mode int32) int32 + +//go:noescape +func nsec(*int64) int64 + +//go:noescape +func sigtramp(ureg, msg unsafe.Pointer) + +func setfpmasks() + +//go:noescape +func tstart_plan9(newm *m) + +func errstr() string + +type _Plink uintptr + +//go:linkname os_sigpipe os.sigpipe +func os_sigpipe() { + throw("too many writes on closed pipe") +} + +func sigpanic() { + g := getg() + if !canpanic(g) { + throw("unexpected signal during runtime execution") + } + + note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig))) + switch g.sig { + case _SIGRFAULT, _SIGWFAULT: + i := index(note, "addr=") + if i >= 0 { + i += 5 + } else if i = index(note, "va="); i >= 0 { + i += 3 + } else { + panicmem() + } + addr := note[i:] + g.sigcode1 = uintptr(atolwhex(addr)) + if g.sigcode1 < 0x1000 || g.paniconfault { + panicmem() + } + print("unexpected fault address ", hex(g.sigcode1), "\n") + throw("fault") + case _SIGTRAP: + if g.paniconfault { + panicmem() + } + throw(note) + case _SIGINTDIV: + panicdivide() + case _SIGFLOAT: + panicfloat() + default: + panic(errorString(note)) + } +} + +func atolwhex(p string) int64 { + for hasprefix(p, " ") || hasprefix(p, "\t") { + p = p[1:] + } + neg := false + if hasprefix(p, "-") || hasprefix(p, "+") { + neg = p[0] == '-' + p = p[1:] + for hasprefix(p, " ") || hasprefix(p, "\t") { + p = p[1:] + } + } + var n int64 + switch { + case hasprefix(p, "0x"), hasprefix(p, "0X"): + p = p[2:] + for ; len(p) > 0; p = p[1:] { + if '0' <= p[0] && p[0] <= '9' { + n = n*16 + int64(p[0]-'0') + } else if 'a' <= p[0] && p[0] <= 'f' { + n = n*16 + int64(p[0]-'a'+10) + } else if 'A' <= p[0] && p[0] <= 'F' { + n = n*16 + int64(p[0]-'A'+10) + } else { + break + } + } + case hasprefix(p, "0"): + for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { + n = n*8 + int64(p[0]-'0') + } + default: + for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { + n = n*10 + int64(p[0]-'0') + } + } + if neg { + n = -n + } + return n +} + type sigset struct{} // Called to initialize a new m (including the bootstrap m). diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index 44830650e12952..47bf8fc20d627d 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -3,35 +3,3 @@ // license that can be found in the LICENSE file. package runtime - -import "unsafe" - -type mOS struct{} - -//go:noescape -func thr_new(param *thrparam, size int32) - -//go:noescape -func sigaltstack(new, old *stackt) - -//go:noescape -func sigaction(sig int32, new, old *sigactiont) - -//go:noescape -func sigprocmask(how int32, new, old *sigset) - -//go:noescape -func setitimer(mode int32, new, old *itimerval) - -//go:noescape -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 - -//go:noescape -func getrlimit(kind int32, limit unsafe.Pointer) int32 -func raise(sig int32) -func raiseproc(sig int32) - -//go:noescape -func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32 - -func osyield() diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index 6f126b4770505e..47bf8fc20d627d 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -3,67 +3,3 @@ // license that can be found in the LICENSE file. package runtime - -import "unsafe" - -type mOS struct { - waitsema int32 // semaphore for parking on locks - waitsemacount int32 - waitsemalock int32 -} - -func nacl_exception_stack(p uintptr, size int32) int32 -func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32 -func nacl_sem_create(flag int32) int32 -func nacl_sem_wait(sem int32) int32 -func nacl_sem_post(sem int32) int32 -func nacl_mutex_create(flag int32) int32 -func nacl_mutex_lock(mutex int32) int32 -func nacl_mutex_trylock(mutex int32) int32 -func nacl_mutex_unlock(mutex int32) int32 -func nacl_cond_create(flag int32) int32 -func nacl_cond_wait(cond, n int32) int32 -func nacl_cond_signal(cond int32) int32 -func nacl_cond_broadcast(cond int32) int32 - -//go:noescape -func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32 -func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32 - -//go:noescape -func nacl_nanosleep(ts, extra *timespec) int32 -func nanotime() int64 -func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer -func exit(code int32) -func osyield() - -//go:noescape -func write(fd uintptr, p unsafe.Pointer, n int32) int32 - -//go:linkname os_sigpipe os.sigpipe -func os_sigpipe() { - throw("too many writes on closed pipe") -} - -func dieFromSignal(sig int32) { - exit(2) -} - -func sigpanic() { - g := getg() - if !canpanic(g) { - throw("unexpected signal during runtime execution") - } - - // Native Client only invokes the exception handler for memory faults. - g.sig = _SIGSEGV - panicmem() -} - -func raiseproc(sig int32) { -} - -// Stubs so tests can link correctly. These should never be called. -func open(name *byte, mode, perm int32) int32 -func closefd(fd int32) int32 -func read(fd int32, p unsafe.Pointer, n int32) int32 diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 3748ed2e514cc1..47bf8fc20d627d 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -3,36 +3,3 @@ // license that can be found in the LICENSE file. package runtime - -type mOS struct { - waitsemacount uint32 -} - -//go:noescape -func setitimer(mode int32, new, old *itimerval) - -//go:noescape -func sigaction(sig int32, new, old *sigactiont) - -//go:noescape -func sigaltstack(new, old *stackt) - -//go:noescape -func sigprocmask(mode int32, new sigset) sigset - -//go:noescape -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 - -func raise(sig int32) -func raiseproc(sig int32) - -//go:noescape -func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32 - -//go:noescape -func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 - -//go:noescape -func thrwakeup(ident uintptr, n int32) int32 - -func osyield() diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 5c43a3bd854b34..47bf8fc20d627d 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -3,148 +3,3 @@ // license that can be found in the LICENSE file. package runtime - -import "unsafe" - -type mOS struct { - waitsemacount uint32 - notesig *int8 - errstr *byte -} - -func closefd(fd int32) int32 - -//go:noescape -func open(name *byte, mode, perm int32) int32 - -//go:noescape -func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 - -//go:noescape -func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 - -func seek(fd int32, offset int64, whence int32) int64 - -//go:noescape -func exits(msg *byte) - -//go:noescape -func brk_(addr unsafe.Pointer) int32 - -func sleep(ms int32) int32 - -func rfork(flags int32) int32 - -//go:noescape -func plan9_semacquire(addr *uint32, block int32) int32 - -//go:noescape -func plan9_tsemacquire(addr *uint32, ms int32) int32 - -//go:noescape -func plan9_semrelease(addr *uint32, count int32) int32 - -//go:noescape -func notify(fn unsafe.Pointer) int32 - -func noted(mode int32) int32 - -//go:noescape -func nsec(*int64) int64 - -//go:noescape -func sigtramp(ureg, msg unsafe.Pointer) - -func setfpmasks() - -//go:noescape -func tstart_plan9(newm *m) - -func errstr() string - -type _Plink uintptr - -//go:linkname os_sigpipe os.sigpipe -func os_sigpipe() { - throw("too many writes on closed pipe") -} - -func sigpanic() { - g := getg() - if !canpanic(g) { - throw("unexpected signal during runtime execution") - } - - note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig))) - switch g.sig { - case _SIGRFAULT, _SIGWFAULT: - i := index(note, "addr=") - if i >= 0 { - i += 5 - } else if i = index(note, "va="); i >= 0 { - i += 3 - } else { - panicmem() - } - addr := note[i:] - g.sigcode1 = uintptr(atolwhex(addr)) - if g.sigcode1 < 0x1000 || g.paniconfault { - panicmem() - } - print("unexpected fault address ", hex(g.sigcode1), "\n") - throw("fault") - case _SIGTRAP: - if g.paniconfault { - panicmem() - } - throw(note) - case _SIGINTDIV: - panicdivide() - case _SIGFLOAT: - panicfloat() - default: - panic(errorString(note)) - } -} - -func atolwhex(p string) int64 { - for hasprefix(p, " ") || hasprefix(p, "\t") { - p = p[1:] - } - neg := false - if hasprefix(p, "-") || hasprefix(p, "+") { - neg = p[0] == '-' - p = p[1:] - for hasprefix(p, " ") || hasprefix(p, "\t") { - p = p[1:] - } - } - var n int64 - switch { - case hasprefix(p, "0x"), hasprefix(p, "0X"): - p = p[2:] - for ; len(p) > 0; p = p[1:] { - if '0' <= p[0] && p[0] <= '9' { - n = n*16 + int64(p[0]-'0') - } else if 'a' <= p[0] && p[0] <= 'f' { - n = n*16 + int64(p[0]-'a'+10) - } else if 'A' <= p[0] && p[0] <= 'F' { - n = n*16 + int64(p[0]-'A'+10) - } else { - break - } - } - case hasprefix(p, "0"): - for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { - n = n*8 + int64(p[0]-'0') - } - default: - for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { - n = n*10 + int64(p[0]-'0') - } - } - if neg { - n = -n - } - return n -} From 258a4c3daf992958f5d7dc5bccf2c5b41e236959 Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Fri, 6 May 2016 14:21:52 +0100 Subject: [PATCH 019/267] syscall,os,net: don't use ForkLock in plan9 This is the follow-on to CL 22610: now that it's the child instead of the parent which lists unwanted fds to close in syscall.StartProcess, plan9 no longer needs the ForkLock to protect the list from changing. The readdupdevice function is also now unused and can be removed. Change-Id: I904c8bbf5dbaa7022b0f1a1de0862cd3064ca8c7 Reviewed-on: https://go-review.googlesource.com/22842 Reviewed-by: David du Colombier <0intro@gmail.com> Run-TryBot: David du Colombier <0intro@gmail.com> Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/fd_plan9.go | 2 - src/net/file_plan9.go | 2 - src/os/file_plan9.go | 5 --- src/syscall/exec_plan9.go | 82 +-------------------------------------- 4 files changed, 1 insertion(+), 90 deletions(-) diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go index 329d6152b2d989..8e272b1eb85e53 100644 --- a/src/net/fd_plan9.go +++ b/src/net/fd_plan9.go @@ -154,9 +154,7 @@ func (l *TCPListener) dup() (*os.File, error) { } func (fd *netFD) file(f *os.File, s string) (*os.File, error) { - syscall.ForkLock.RLock() dfd, err := syscall.Dup(int(f.Fd()), -1) - syscall.ForkLock.RUnlock() if err != nil { return nil, os.NewSyscallError("dup", err) } diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go index 24efdc5186d89f..2939c09a43097f 100644 --- a/src/net/file_plan9.go +++ b/src/net/file_plan9.go @@ -50,9 +50,7 @@ func newFileFD(f *os.File) (net *netFD, err error) { name := comp[2] switch file := comp[n-1]; file { case "ctl", "clone": - syscall.ForkLock.RLock() fd, err := syscall.Dup(int(f.Fd()), -1) - syscall.ForkLock.RUnlock() if err != nil { return nil, os.NewSyscallError("dup", err) } diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go index fb796a2a89bcba..9edb6bc0747d08 100644 --- a/src/os/file_plan9.go +++ b/src/os/file_plan9.go @@ -146,11 +146,9 @@ func (file *file) close() error { return ErrInvalid } var err error - syscall.ForkLock.RLock() if e := syscall.Close(file.fd); e != nil { err = &PathError{"close", file.name, e} } - syscall.ForkLock.RUnlock() file.fd = -1 // so it can't be closed again // no need for a finalizer anymore @@ -420,12 +418,9 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error { func Pipe() (r *File, w *File, err error) { var p [2]int - syscall.ForkLock.RLock() if e := syscall.Pipe(p[0:]); e != nil { - syscall.ForkLock.RUnlock() return nil, nil, NewSyscallError("pipe", e) } - syscall.ForkLock.RUnlock() return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil } diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go index 58e5a3c623b62a..6551bcb1c1f215 100644 --- a/src/syscall/exec_plan9.go +++ b/src/syscall/exec_plan9.go @@ -12,53 +12,7 @@ import ( "unsafe" ) -// Lock synchronizing creation of new file descriptors with fork. -// -// We want the child in a fork/exec sequence to inherit only the -// file descriptors we intend. To do that, we mark all file -// descriptors close-on-exec and then, in the child, explicitly -// unmark the ones we want the exec'ed program to keep. -// Unix doesn't make this easy: there is, in general, no way to -// allocate a new file descriptor close-on-exec. Instead you -// have to allocate the descriptor and then mark it close-on-exec. -// If a fork happens between those two events, the child's exec -// will inherit an unwanted file descriptor. -// -// This lock solves that race: the create new fd/mark close-on-exec -// operation is done holding ForkLock for reading, and the fork itself -// is done holding ForkLock for writing. At least, that's the idea. -// There are some complications. -// -// Some system calls that create new file descriptors can block -// for arbitrarily long times: open on a hung NFS server or named -// pipe, accept on a socket, and so on. We can't reasonably grab -// the lock across those operations. -// -// It is worse to inherit some file descriptors than others. -// If a non-malicious child accidentally inherits an open ordinary file, -// that's not a big deal. On the other hand, if a long-lived child -// accidentally inherits the write end of a pipe, then the reader -// of that pipe will not see EOF until that child exits, potentially -// causing the parent program to hang. This is a common problem -// in threaded C programs that use popen. -// -// Luckily, the file descriptors that are most important not to -// inherit are not the ones that can take an arbitrarily long time -// to create: pipe returns instantly, and the net package uses -// non-blocking I/O to accept on a listening socket. -// The rules for which file descriptor-creating operations use the -// ForkLock are as follows: -// -// 1) Pipe. Does not block. Use the ForkLock. -// 2) Socket. Does not block. Use the ForkLock. -// 3) Accept. If using non-blocking mode, use the ForkLock. -// Otherwise, live with the race. -// 4) Open. Can block. Use O_CLOEXEC if available (Linux). -// Otherwise, live with the race. -// 5) Dup. Does not block. Use the ForkLock. -// On Linux, could use fcntl F_DUPFD_CLOEXEC -// instead of the ForkLock, but only for dup(fd, -1). - +// ForkLock is not used on plan9. var ForkLock sync.RWMutex // gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order. @@ -151,35 +105,6 @@ func readdirnames(dirfd int) (names []string, err error) { return } -// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d. -// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read. -func readdupdevice() (fds []int, err error) { - dupdevfd, err := Open("#d", O_RDONLY) - if err != nil { - return - } - defer Close(dupdevfd) - - names, err := readdirnames(dupdevfd) - if err != nil { - return - } - - fds = make([]int, 0, len(names)/2) - for _, name := range names { - if n := len(name); n > 3 && name[n-3:n] == "ctl" { - continue - } - fd := int(atoi([]byte(name))) - switch fd { - case 0, 1, 2, dupdevfd: - continue - } - fds = append(fds, fd) - } - return -} - // name of the directory containing names and control files for all open file descriptors var dupdev, _ = BytePtrFromString("#d") @@ -492,9 +417,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) } } - // Acquire the fork lock to prevent other threads from creating new fds before we fork. - ForkLock.Lock() - // Allocate child status pipe close on exec. e := cexecPipe(p[:]) @@ -510,10 +432,8 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) Close(p[0]) Close(p[1]) } - ForkLock.Unlock() return 0, err } - ForkLock.Unlock() // Read child error status from pipe. Close(p[1]) From c81a3532fea42df33dea54497dfaa96873c2d976 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 15 Apr 2016 00:33:28 +0300 Subject: [PATCH 020/267] cmd/vet: check sync.* types' copying Embed noLock struct into the following types, so `go vet -copylocks` catches their copying additionally to types containing sync.Mutex: - sync.Cond - sync.WaitGroup - sync.Pool - atomic.Value Fixes #14582 Change-Id: Icb543ef5ad10524ad239a15eec8a9b334b0e0660 Reviewed-on: https://go-review.googlesource.com/22015 Reviewed-by: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/cmd/vet/testdata/copylock.go | 74 +++++++++++++++++++++++++++++++- src/sync/atomic/value.go | 14 ++++++ src/sync/cond.go | 12 ++++++ src/sync/mutex.go | 2 + src/sync/pool.go | 3 ++ src/sync/rwmutex.go | 2 + src/sync/waitgroup.go | 4 ++ 7 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/cmd/vet/testdata/copylock.go b/src/cmd/vet/testdata/copylock.go index cf56802cdbb249..d49f4686275871 100644 --- a/src/cmd/vet/testdata/copylock.go +++ b/src/cmd/vet/testdata/copylock.go @@ -1,6 +1,9 @@ package testdata -import "sync" +import ( + "sync" + "sync/atomic" +) func OkFunc() { var x *sync.Mutex @@ -66,3 +69,72 @@ func BadFunc() { new := func(interface{}) {} new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex" } + +// SyncTypesCheck checks copying of sync.* types except sync.Mutex +func SyncTypesCheck() { + // sync.RWMutex copying + var rwmuX sync.RWMutex + var rwmuXX = sync.RWMutex{} + rwmuX1 := new(sync.RWMutex) + rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" + rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" + var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex" + rwmuP := &rwmuX + rwmuZ := &sync.RWMutex{} + + // sync.Cond copying + var condX sync.Cond + var condXX = sync.Cond{} + condX1 := new(sync.Cond) + condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" + condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" + var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy" + condP := &condX + condZ := &sync.Cond{ + L: &sync.Mutex{}, + } + condZ = sync.NewCond(&sync.Mutex{}) + + // sync.WaitGroup copying + var wgX sync.WaitGroup + var wgXX = sync.WaitGroup{} + wgX1 := new(sync.WaitGroup) + wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" + wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" + var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy" + wgP := &wgX + wgZ := &sync.WaitGroup{} + + // sync.Pool copying + var poolX sync.Pool + var poolXX = sync.Pool{} + poolX1 := new(sync.Pool) + poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" + poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" + var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy" + poolP := &poolX + poolZ := &sync.Pool{} + + // sync.Once copying + var onceX sync.Once + var onceXX = sync.Once{} + onceX1 := new(sync.Once) + onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" + onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" + var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex" + onceP := &onceX + onceZ := &sync.Once{} +} + +// AtomicTypesCheck checks copying of sync/atomic types +func AtomicTypesCheck() { + // atomic.Value copying + var vX atomic.Value + var vXX = atomic.Value{} + vX1 := new(atomic.Value) + vY := vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy" + vY = vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy" + var vYY = vX // ERROR "variable declaration copies lock value to vYY: sync/atomic.Value contains sync/atomic.noCopy" + vP := &vX + vZ := &atomic.Value{} +} diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go index ab3aa11285478f..30abf726344e96 100644 --- a/src/sync/atomic/value.go +++ b/src/sync/atomic/value.go @@ -12,7 +12,11 @@ import ( // Values can be created as part of other data structures. // The zero value for a Value returns nil from Load. // Once Store has been called, a Value must not be copied. +// +// A Value must not be copied after first use. type Value struct { + noCopy noCopy + v interface{} } @@ -83,3 +87,13 @@ func (v *Value) Store(x interface{}) { // Disable/enable preemption, implemented in runtime. func runtime_procPin() func runtime_procUnpin() + +// noCopy may be embedded into structs which must not be copied +// after the first use. +// +// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// for details. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} diff --git a/src/sync/cond.go b/src/sync/cond.go index f711c39da2d856..c070d9d84ef9e5 100644 --- a/src/sync/cond.go +++ b/src/sync/cond.go @@ -20,6 +20,8 @@ import ( // A Cond can be created as part of other structures. // A Cond must not be copied after first use. type Cond struct { + noCopy noCopy + // L is held while observing or changing the condition L Locker @@ -84,3 +86,13 @@ func (c *copyChecker) check() { panic("sync.Cond is copied") } } + +// noCopy may be embedded into structs which must not be copied +// after the first use. +// +// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// for details. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} diff --git a/src/sync/mutex.go b/src/sync/mutex.go index 78b115cf5a1972..90892793f0a99c 100644 --- a/src/sync/mutex.go +++ b/src/sync/mutex.go @@ -19,6 +19,8 @@ import ( // A Mutex is a mutual exclusion lock. // Mutexes can be created as part of other structures; // the zero value for a Mutex is an unlocked mutex. +// +// A Mutex must not be copied after first use. type Mutex struct { state int32 sema uint32 diff --git a/src/sync/pool.go b/src/sync/pool.go index 2acf505f3c96b9..bf29d88c5cb6cc 100644 --- a/src/sync/pool.go +++ b/src/sync/pool.go @@ -40,7 +40,10 @@ import ( // that scenario. It is more efficient to have such objects implement their own // free list. // +// A Pool must not be copied after first use. type Pool struct { + noCopy noCopy + local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal localSize uintptr // size of the local array diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go index 9fc6e3bd2c5151..455d412330034e 100644 --- a/src/sync/rwmutex.go +++ b/src/sync/rwmutex.go @@ -16,6 +16,8 @@ import ( // RWMutexes can be created as part of other // structures; the zero value for a RWMutex is // an unlocked mutex. +// +// An RWMutex must not be copied after first use. type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // semaphore for writers to wait for completing readers diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go index 029e6077cde714..b386e1fec2b61a 100644 --- a/src/sync/waitgroup.go +++ b/src/sync/waitgroup.go @@ -15,7 +15,11 @@ import ( // goroutines to wait for. Then each of the goroutines // runs and calls Done when finished. At the same time, // Wait can be used to block until all goroutines have finished. +// +// A WaitGroup must not be copied after first use. type WaitGroup struct { + noCopy noCopy + // 64-bit value: high 32 bits are counter, low 32 bits are waiter count. // 64-bit atomic operations require 64-bit alignment, but 32-bit // compilers do not ensure it. So we allocate 12 bytes and then use From a5c5f6ea94dcd9caad0f0df8caaf68f8659900b2 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Fri, 6 May 2016 18:16:52 +0200 Subject: [PATCH 021/267] all: fix copy-and-paste errors in tests Fixes #15570 Change-Id: I95d1ac26e342c3bbf36ad1f0209711ea96eaf487 Reviewed-on: https://go-review.googlesource.com/22870 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/encoding/gob/codec_test.go | 4 ++-- src/net/conn_test.go | 2 +- src/net/mockserver_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go index b772171f930adc..d4002cbccab3d3 100644 --- a/src/encoding/gob/codec_test.go +++ b/src/encoding/gob/codec_test.go @@ -1253,7 +1253,7 @@ func TestIgnoreInterface(t *testing.T) { if item2.I != item1.I { t.Error("normal int did not decode correctly") } - if item2.F != item2.F { + if item2.F != item1.F { t.Error("normal float did not decode correctly") } } @@ -1280,7 +1280,7 @@ func TestUnexportedFields(t *testing.T) { if err != nil { t.Fatal("decode error:", err) } - if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D { + if u0.A != u1.A || u0.B != u1.B || u0.D != u1.D { t.Errorf("u1->u0: expected %v; got %v", u0, u1) } if u1.c != 1234. { diff --git a/src/net/conn_test.go b/src/net/conn_test.go index 8accbae7bb8c47..16cf69ee169eaf 100644 --- a/src/net/conn_test.go +++ b/src/net/conn_test.go @@ -43,7 +43,7 @@ func TestConnAndListener(t *testing.T) { t.Fatal(err) } defer c.Close() - if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network { + if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network { t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) } c.SetDeadline(time.Now().Add(someTimeout)) diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go index 9e6907c09a24cb..b67dd916506043 100644 --- a/src/net/mockserver_test.go +++ b/src/net/mockserver_test.go @@ -228,7 +228,7 @@ func transponder(ln Listener, ch chan<- error) { defer c.Close() network := ln.Addr().Network() - if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network { + if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network { ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) return } From 61602b0e9e1daa0490793ef9ada3a51f8f482265 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 16:06:02 +0000 Subject: [PATCH 022/267] runtime: delete empty files I meant to delete these in CL 22850, actually. Change-Id: I0c286efd2b9f1caf0221aa88e3bcc03649c89517 Reviewed-on: https://go-review.googlesource.com/22851 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/os_freebsd.go | 5 ----- src/runtime/os_nacl.go | 5 ----- src/runtime/os_openbsd.go | 5 ----- src/runtime/os_plan9.go | 5 ----- 4 files changed, 20 deletions(-) delete mode 100644 src/runtime/os_freebsd.go delete mode 100644 src/runtime/os_nacl.go delete mode 100644 src/runtime/os_openbsd.go delete mode 100644 src/runtime/os_plan9.go diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go deleted file mode 100644 index 47bf8fc20d627d..00000000000000 --- a/src/runtime/os_freebsd.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go deleted file mode 100644 index 47bf8fc20d627d..00000000000000 --- a/src/runtime/os_nacl.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go deleted file mode 100644 index 47bf8fc20d627d..00000000000000 --- a/src/runtime/os_openbsd.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go deleted file mode 100644 index 47bf8fc20d627d..00000000000000 --- a/src/runtime/os_plan9.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime From 1ff57143af65014c80e39cc0f19cd97a455f5b49 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 16:24:57 +0000 Subject: [PATCH 023/267] net: ignore network failures on some builders We run the external network tests on builders, but some of our builders have less-than-ideal DNS connectivity. This change continues to run the tests on all builders, but marks certain builders as flaky (network-wise), and only validates their DNS results if they got DNS results. Change-Id: I826dc2a6f6da55add89ae9c6db892b3b2f7b526b Reviewed-on: https://go-review.googlesource.com/22852 Reviewed-by: Ian Lance Taylor --- src/internal/testenv/testenv.go | 7 +++++++ src/net/lookup_test.go | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 9e684e3034388e..f134f6b04a185f 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -16,6 +16,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strconv" "strings" "testing" ) @@ -133,3 +134,9 @@ func SkipFlaky(t *testing.T, issue int) { t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue) } } + +func SkipFlakyNet(t *testing.T) { + if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v { + t.Skip("skipping test on builder known to have frequent network failures") + } +} diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 6e54fdba76d902..fb3cf18d3bd972 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -498,6 +498,7 @@ func TestLookupDotsWithRemoteSource(t *testing.T) { func testDots(t *testing.T, mode string) { names, err := LookupAddr("8.8.8.8") // Google dns server if err != nil { + testenv.SkipFlakyNet(t) t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) } else { for _, name := range names { @@ -509,12 +510,16 @@ func testDots(t *testing.T, mode string) { } cname, err := LookupCNAME("www.mit.edu") - if err != nil || !strings.HasSuffix(cname, ".") { - t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode) + if err != nil { + testenv.SkipFlakyNet(t) + t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err) + } else if !strings.HasSuffix(cname, ".") { + t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode) } mxs, err := LookupMX("google.com") if err != nil { + testenv.SkipFlakyNet(t) t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode) } else { for _, mx := range mxs { @@ -527,6 +532,7 @@ func testDots(t *testing.T, mode string) { nss, err := LookupNS("google.com") if err != nil { + testenv.SkipFlakyNet(t) t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode) } else { for _, ns := range nss { @@ -539,6 +545,7 @@ func testDots(t *testing.T, mode string) { cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com") if err != nil { + testenv.SkipFlakyNet(t) t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode) } else { if !strings.HasSuffix(cname, ".google.com.") { From 131231b8db26b38c9c2fdc52fb788241f5c2de51 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 16:07:11 +0000 Subject: [PATCH 024/267] os: rename remaining four os1_*.go files to os_*.go Change-Id: Ice9c234960adc7857c8370b777a0b18e29d59281 Reviewed-on: https://go-review.googlesource.com/22853 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/{os1_freebsd.go => os_freebsd.go} | 0 src/runtime/{os1_nacl.go => os_nacl.go} | 0 src/runtime/{os1_openbsd.go => os_openbsd.go} | 0 src/runtime/{os1_plan9.go => os_plan9.go} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/runtime/{os1_freebsd.go => os_freebsd.go} (100%) rename src/runtime/{os1_nacl.go => os_nacl.go} (100%) rename src/runtime/{os1_openbsd.go => os_openbsd.go} (100%) rename src/runtime/{os1_plan9.go => os_plan9.go} (100%) diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os_freebsd.go similarity index 100% rename from src/runtime/os1_freebsd.go rename to src/runtime/os_freebsd.go diff --git a/src/runtime/os1_nacl.go b/src/runtime/os_nacl.go similarity index 100% rename from src/runtime/os1_nacl.go rename to src/runtime/os_nacl.go diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os_openbsd.go similarity index 100% rename from src/runtime/os1_openbsd.go rename to src/runtime/os_openbsd.go diff --git a/src/runtime/os1_plan9.go b/src/runtime/os_plan9.go similarity index 100% rename from src/runtime/os1_plan9.go rename to src/runtime/os_plan9.go From 670a5cda2048af8d83958af0f4b2fda8f7b4ea72 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 6 May 2016 15:28:19 +0000 Subject: [PATCH 025/267] Revert "testing/quick: generate more map and slice states" This reverts commit 0ccabe2e0b42a2602e0f37ce28d5368aa811f530. Change-Id: Ib1c230fb6801c0ee26f4a352b0c1130fa240a76a Reviewed-on: https://go-review.googlesource.com/22860 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/testing/quick/quick.go | 47 +++++++++++++-------------------- src/testing/quick/quick_test.go | 17 ++++++++++++ 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go index 4bc8e3fc2e1479..798d41aa7d176b 100644 --- a/src/testing/quick/quick.go +++ b/src/testing/quick/quick.go @@ -14,7 +14,7 @@ import ( "strings" ) -var defaultMaxCount = flag.Int("quickchecks", 100, "The default number of iterations for each check") +var defaultMaxCount *int = 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,22 +98,18 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value, case reflect.Uintptr: v.SetUint(uint64(randInt64(rand))) case reflect.Map: - 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) + 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) } case reflect.Ptr: - if generateNilValue(rand) { + if rand.Intn(size) == 0 { v.Set(reflect.Zero(concrete)) // Generate nil pointer. } else { elem, ok := sizedValue(concrete.Elem(), rand, size) @@ -124,20 +120,15 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value, v.Elem().Set(elem) } case reflect.Slice: - 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) + 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 } + v.Index(i).Set(elem) } case reflect.Array: for i := 0; i < v.Len(); i++ { @@ -385,5 +376,3 @@ func toString(interfaces []interface{}) string { } return strings.Join(s, ", ") } - -func generateNilValue(r *rand.Rand) bool { return r.Intn(20) == 0 } diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go index 018ece2a5289ed..fe443592f87bed 100644 --- a/src/testing/quick/quick_test.go +++ b/src/testing/quick/quick_test.go @@ -290,3 +290,20 @@ 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) + } +} From 31283dd4836542f94b063bfd2886fc32639358f7 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 18:11:38 +0000 Subject: [PATCH 026/267] net/http: don't assume Response.Request is populated after redirect errors Fixes #15577 Change-Id: I5f023790a393b17235db2e66c02c2483773ddc1a Reviewed-on: https://go-review.googlesource.com/22857 Reviewed-by: Russ Cox Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/client.go | 2 +- src/net/http/client_test.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index f8ab675a3de047..1127634beca3b9 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -442,7 +442,7 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo req.closeBody() method := valueOrDefault(reqs[0].Method, "GET") var urlStr string - if resp != nil { + if resp != nil && resp.Request != nil { urlStr = resp.Request.URL.String() } else { urlStr = req.URL.String() diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index a9b30b1bf5c134..6f7ab965cbcf94 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1168,3 +1168,26 @@ func TestReferer(t *testing.T) { } } } + +// issue15577Tripper returns a Response with a redirect response +// header and doesn't populate its Response.Request field. +type issue15577Tripper struct{} + +func (issue15577Tripper) RoundTrip(*Request) (*Response, error) { + resp := &Response{ + StatusCode: 303, + Header: map[string][]string{"Location": {"http://www.example.com/"}}, + Body: ioutil.NopCloser(strings.NewReader("")), + } + return resp, nil +} + +// Issue 15577: don't assume the roundtripper's response populates its Request field. +func TestClientRedirectResponseWithoutRequest(t *testing.T) { + c := &Client{ + CheckRedirect: func(*Request, []*Request) error { return fmt.Errorf("no redirects!") }, + Transport: issue15577Tripper{}, + } + // Check that this doesn't crash: + c.Get("http://dummy.tld") +} From 4eccc77f196edfa7646b0e92a11ef8d96ef85b57 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 18:21:22 +0000 Subject: [PATCH 027/267] net/http: wait longer for subprocess to startup in test Might deflake the occasional linux-amd64-race failures. Change-Id: I273b0e32bb92236168eb99887b166e079799c1f1 Reviewed-on: https://go-review.googlesource.com/22858 Reviewed-by: Ian Lance Taylor --- src/net/http/serve_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 661f355d0dd709..b34875f061a062 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -4268,7 +4268,7 @@ func BenchmarkClient(b *testing.B) { // Wait for the server process to respond. url := "http://localhost:" + port + "/" for i := 0; i < 100; i++ { - time.Sleep(50 * time.Millisecond) + time.Sleep(100 * time.Millisecond) if _, err := getNoBody(url); err == nil { break } From f0e2d32fde77ad03616304ab42b8c7426cf3a350 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 6 May 2016 15:34:25 +0000 Subject: [PATCH 028/267] Revert "net/url: validate ports in IPv4 addresses" This reverts commit 9f1ccd647fcdb1b703c1042c90434e15aff75013. For #14860. Change-Id: I63522a4dda8915dc8b972ae2e12495553ed65f09 Reviewed-on: https://go-review.googlesource.com/22861 Reviewed-by: Brad Fitzpatrick Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/net/url/url.go | 6 +----- src/net/url/url_test.go | 6 ++---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index 05b41fa964a9cc..d9c8c49e94a483 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -573,12 +573,8 @@ func parseHost(host string) (string, error) { } return host1 + host2 + host3, nil } - } else if i := strings.LastIndex(host, ":"); i > 0 { - colonPort := host[i:] - if !validOptionalPort(colonPort) { - return "", fmt.Errorf("invalid port %q after host", colonPort) - } } + var err error if host, err = unescape(host, encodeHost); err != nil { return "", err diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index da6bc2843e52b0..7560f22c4a1e2a 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -418,10 +418,10 @@ var urltests = []URLTest{ }, // worst case host, still round trips { - "scheme://!$&'()*+,;=hello!:8080/path", + "scheme://!$&'()*+,;=hello!:port/path", &URL{ Scheme: "scheme", - Host: "!$&'()*+,;=hello!:8080", + Host: "!$&'()*+,;=hello!:port", Path: "/path", }, "", @@ -636,10 +636,8 @@ var parseRequestURLTests = []struct { {"*", true}, {"http://192.168.0.1/", true}, {"http://192.168.0.1:8080/", true}, - {"http://192.168.0.1:foo/", false}, {"http://[fe80::1]/", true}, {"http://[fe80::1]:8080/", true}, - {"http://[fe80::1]:foo/", false}, // Tests exercising RFC 6874 compliance: {"http://[fe80::1%25en0]/", true}, // with alphanum zone identifier From a1813ae0a091e1b880c0d3472112d2c725c2fa18 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 May 2016 11:32:18 -0700 Subject: [PATCH 029/267] misc/cgo/testcarchive: avoid possible pthread_create race The old code assumed that the thread ID set by pthread_create would be available in the newly created thread. While that is clearly true eventually, it is not necessarily true immediately. Rather than try to pass down the thread ID, just call pthread_self in the created thread. Fixes #15576 (I hope). Change-Id: Ic07086b00e4fd5676c04719a299c583320da64a1 Reviewed-on: https://go-review.googlesource.com/22880 Run-TryBot: Ian Lance Taylor Reviewed-by: Brad Fitzpatrick --- misc/cgo/testcarchive/main4.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/misc/cgo/testcarchive/main4.c b/misc/cgo/testcarchive/main4.c index 2aaf09b7c1961e..353f980c50d47e 100644 --- a/misc/cgo/testcarchive/main4.c +++ b/misc/cgo/testcarchive/main4.c @@ -44,8 +44,7 @@ static void init() { // Test raising SIGIO on a C thread with an alternate signal stack // when there is a Go signal handler for SIGIO. -static void* thread1(void* arg) { - pthread_t* ptid = (pthread_t*)(arg); +static void* thread1(void* arg __attribute__ ((unused))) { stack_t ss; int i; stack_t nss; @@ -65,7 +64,7 @@ static void* thread1(void* arg) { // Send ourselves a SIGIO. This will be caught by the Go // signal handler which should forward to the C signal // handler. - i = pthread_kill(*ptid, SIGIO); + i = pthread_kill(pthread_self(), SIGIO); if (i != 0) { fprintf(stderr, "pthread_kill: %s\n", strerror(i)); exit(EXIT_FAILURE); @@ -101,11 +100,11 @@ static void* thread1(void* arg) { // Test calling a Go function to raise SIGIO on a C thread with an // alternate signal stack when there is a Go signal handler for SIGIO. -static void* thread2(void* arg) { - pthread_t* ptid = (pthread_t*)(arg); +static void* thread2(void* arg __attribute__ ((unused))) { stack_t ss; int i; int oldcount; + pthread_t tid; stack_t nss; // Set up an alternate signal stack for this thread. @@ -124,7 +123,8 @@ static void* thread2(void* arg) { // Call a Go function that will call a C function to send us a // SIGIO. - GoRaiseSIGIO(ptid); + tid = pthread_self(); + GoRaiseSIGIO(&tid); // Wait until the signal has been delivered. i = 0; @@ -161,7 +161,7 @@ int main(int argc, char **argv) { // Tell the Go library to start looking for SIGIO. GoCatchSIGIO(); - i = pthread_create(&tid, NULL, thread1, (void*)(&tid)); + i = pthread_create(&tid, NULL, thread1, NULL); if (i != 0) { fprintf(stderr, "pthread_create: %s\n", strerror(i)); exit(EXIT_FAILURE); @@ -173,7 +173,7 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - i = pthread_create(&tid, NULL, thread2, (void*)(&tid)); + i = pthread_create(&tid, NULL, thread2, NULL); if (i != 0) { fprintf(stderr, "pthread_create: %s\n", strerror(i)); exit(EXIT_FAILURE); From 7c5c6645d2ac21073b146c3d1a83c9b8c6463c25 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 18:46:35 +0000 Subject: [PATCH 030/267] net: skip more flaky net tests on flaky net builders e.g. https://storage.googleapis.com/go-build-log/9b937dd8/linux-arm_df54a25a.log Change-Id: Ic5864c7bd840b4f0c6341f919fcbcd5c708b14e7 Reviewed-on: https://go-review.googlesource.com/22881 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/net/lookup_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index fb3cf18d3bd972..7dba393cee5c9e 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -70,6 +70,7 @@ func TestLookupGoogleSRV(t *testing.T) { for _, tt := range lookupGoogleSRVTests { cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name) if err != nil { + testenv.SkipFlakyNet(t) t.Fatal(err) } if len(srvs) == 0 { @@ -137,6 +138,7 @@ func TestLookupGmailNS(t *testing.T) { for _, tt := range lookupGmailNSTests { nss, err := LookupNS(tt.name) if err != nil { + testenv.SkipFlakyNet(t) t.Fatal(err) } if len(nss) == 0 { From 83676d694b64205e80c042ca7cf61f7ad4de6c62 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 6 May 2016 18:33:39 +0000 Subject: [PATCH 031/267] net/url: remove RFC 3986 mention in package comment Change-Id: Ifd707a4bbfcb1721655b4fce2045f3b043e66818 Reviewed-on: https://go-review.googlesource.com/22859 Reviewed-by: Russ Cox --- src/net/url/url.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index d9c8c49e94a483..30e92779370393 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -3,9 +3,13 @@ // license that can be found in the LICENSE file. // Package url parses URLs and implements query escaping. -// See RFC 3986. package url +// See RFC 3986. This package generally follows RFC 3986, except where +// it deviates for compatibility reasons. When sending changes, first +// search old issues for history on decisions. Unit tests should also +// contain references to issue numbers with details. + import ( "bytes" "errors" From e6ec82067a9068c93db6e7041017060a1c863452 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 9 Mar 2016 10:00:12 +0100 Subject: [PATCH 032/267] runtime: use entire address space on 32 bit In issue #13992, Russ mentioned that the heap bitmap footprint was halved but that the bitmap size calculation hadn't been updated. This presents the opportunity to either halve the bitmap size or double the addressable virtual space. This CL doubles the addressable virtual space. On 32 bit this can be tweaked further to allow the bitmap to cover the entire 4GB virtual address space, removing a failure mode if the kernel hands out memory with a too low address. First, fix the calculation and double _MaxArena32 to cover 4GB virtual memory space with the same bitmap size (256 MB). Then, allow the fallback mode for the initial memory reservation on 32 bit (or 64 bit with too little available virtual memory) to not include space for the arena. mheap.sysAlloc will automatically reserve additional space when the existing arena is full. Finally, set arena_start to 0 in 32 bit mode, so that any address is acceptable for subsequent (additional) reservations. Before, the bitmap was always located just before arena_start, so fix the two places relying on that assumption: Point the otherwise unused mheap.bitmap to one byte after the end of the bitmap, and use it for bitmap addressing instead of arena_start. With arena_start set to 0 on 32 bit, the cgoInRange check is no longer a sufficient check for Go pointers. Introduce and call inHeapOrStack to check whether a pointer is to the Go heap or stack. While we're here, remove sysReserveHigh which seems to be unused. Fixes #13992 Change-Id: I592b513148a50b9d3967b5c5d94b86b3ec39acc2 Reviewed-on: https://go-review.googlesource.com/20471 Reviewed-by: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot --- src/runtime/cgocall.go | 2 +- src/runtime/malloc.go | 76 +++++++++++++++--------------------------- src/runtime/mbitmap.go | 4 +-- src/runtime/mheap.go | 24 ++++++++++++- 4 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 8457fb2de73c71..1e0d4c7f19504a 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -601,7 +601,7 @@ func cgoIsGoPointer(p unsafe.Pointer) bool { return false } - if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) { + if inHeapOrStack(uintptr(p)) { return true } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index bb17919fd0135d..ae81b8681b90d1 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -170,7 +170,7 @@ const ( _MaxGcproc = 32 ) -const _MaxArena32 = 2 << 30 +const _MaxArena32 = 1<<32 - 1 // OS-defined helpers: // @@ -227,7 +227,7 @@ func mallocinit() { // Set up the allocation arena, a contiguous area of memory where // allocated data will be found. The arena begins with a bitmap large - // enough to hold 4 bits per allocated word. + // enough to hold 2 bits per allocated word. if sys.PtrSize == 8 && (limit == 0 || limit > 1<<30) { // On a 64-bit machine, allocate from a single contiguous reservation. // 512 GB (MaxMem) should be big enough for now. @@ -259,7 +259,7 @@ func mallocinit() { // translation buffers, the user address space is limited to 39 bits // On darwin/arm64, the address space is even smaller. arenaSize := round(_MaxMem, _PageSize) - bitmapSize = arenaSize / (sys.PtrSize * 8 / 4) + bitmapSize = arenaSize / (sys.PtrSize * 8 / 2) spansSize = arenaSize / _PageSize * sys.PtrSize spansSize = round(spansSize, _PageSize) for i := 0; i <= 0x7f; i++ { @@ -284,32 +284,26 @@ func mallocinit() { // with a giant virtual address space reservation. // Instead we map the memory information bitmap // immediately after the data segment, large enough - // to handle another 2GB of mappings (256 MB), + // to handle the entire 4GB address space (256 MB), // along with a reservation for an initial arena. // When that gets used up, we'll start asking the kernel - // for any memory anywhere and hope it's in the 2GB - // following the bitmap (presumably the executable begins - // near the bottom of memory, so we'll have to use up - // most of memory before the kernel resorts to giving out - // memory before the beginning of the text segment). - // - // Alternatively we could reserve 512 MB bitmap, enough - // for 4GB of mappings, and then accept any memory the - // kernel threw at us, but normally that's a waste of 512 MB - // of address space, which is probably too much in a 32-bit world. + // for any memory anywhere. // If we fail to allocate, try again with a smaller arena. // This is necessary on Android L where we share a process // with ART, which reserves virtual memory aggressively. + // In the worst case, fall back to a 0-sized initial arena, + // in the hope that subsequent reservations will succeed. arenaSizes := []uintptr{ 512 << 20, 256 << 20, 128 << 20, + 0, } for _, arenaSize := range arenaSizes { - bitmapSize = _MaxArena32 / (sys.PtrSize * 8 / 4) - spansSize = _MaxArena32 / _PageSize * sys.PtrSize + bitmapSize = (_MaxArena32 + 1) / (sys.PtrSize * 8 / 2) + spansSize = (_MaxArena32 + 1) / _PageSize * sys.PtrSize if limit > 0 && arenaSize+bitmapSize+spansSize > limit { bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1) arenaSize = bitmapSize * 8 @@ -344,10 +338,16 @@ func mallocinit() { p1 := round(p, _PageSize) mheap_.spans = (**mspan)(unsafe.Pointer(p1)) - mheap_.bitmap = p1 + spansSize - mheap_.arena_start = p1 + (spansSize + bitmapSize) - mheap_.arena_used = mheap_.arena_start + mheap_.bitmap = p1 + spansSize + bitmapSize + if sys.PtrSize == 4 { + // Set arena_start such that we can accept memory + // reservations located anywhere in the 4GB virtual space. + mheap_.arena_start = 0 + } else { + mheap_.arena_start = p1 + (spansSize + bitmapSize) + } mheap_.arena_end = p + pSize + mheap_.arena_used = p1 + (spansSize + bitmapSize) mheap_.arena_reserved = reserved if mheap_.arena_start&(_PageSize-1) != 0 { @@ -361,29 +361,6 @@ func mallocinit() { _g_.m.mcache = allocmcache() } -// sysReserveHigh reserves space somewhere high in the address space. -// sysReserve doesn't actually reserve the full amount requested on -// 64-bit systems, because of problems with ulimit. Instead it checks -// that it can get the first 64 kB and assumes it can grab the rest as -// needed. This doesn't work well with the "let the kernel pick an address" -// mode, so don't do that. Pick a high address instead. -func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer { - if sys.PtrSize == 4 { - return sysReserve(nil, n, reserved) - } - - for i := 0; i <= 0x7f; i++ { - p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32) - *reserved = false - p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved)) - if p != 0 { - return unsafe.Pointer(p) - } - } - - return sysReserve(nil, n, reserved) -} - // sysAlloc allocates the next n bytes from the heap arena. The // returned pointer is always _PageSize aligned and between // h.arena_start and h.arena_end. sysAlloc returns nil on failure. @@ -394,7 +371,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer { // Reserve some more space. p_size := round(n+_PageSize, 256<<20) new_end := h.arena_end + p_size // Careful: can overflow - if h.arena_end <= new_end && new_end <= h.arena_start+_MaxArena32 { + if h.arena_end <= new_end && new_end-h.arena_start-1 <= _MaxArena32 { // TODO: It would be bad if part of the arena // is reserved and part is not. var reserved bool @@ -405,7 +382,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer { if p == h.arena_end { h.arena_end = new_end h.arena_reserved = reserved - } else if h.arena_start <= p && p+p_size <= h.arena_start+_MaxArena32 { + } else if h.arena_start <= p && p+p_size-h.arena_start-1 <= _MaxArena32 { // Keep everything page-aligned. // Our pages are bigger than hardware pages. h.arena_end = p + p_size @@ -442,23 +419,22 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer { } // If using 64-bit, our reservation is all we have. - if h.arena_end-h.arena_start >= _MaxArena32 { + if h.arena_end-h.arena_start > _MaxArena32 { return nil } // On 32-bit, once the reservation is gone we can - // try to get memory at a location chosen by the OS - // and hope that it is in the range we allocated bitmap for. + // try to get memory at a location chosen by the OS. p_size := round(n, _PageSize) + _PageSize p := uintptr(sysAlloc(p_size, &memstats.heap_sys)) if p == 0 { return nil } - if p < h.arena_start || p+p_size-h.arena_start >= _MaxArena32 { + if p < h.arena_start || p+p_size-h.arena_start > _MaxArena32 { top := ^uintptr(0) - if top-h.arena_start > _MaxArena32 { - top = h.arena_start + _MaxArena32 + if top-h.arena_start-1 > _MaxArena32 { + top = h.arena_start + _MaxArena32 + 1 } print("runtime: memory allocated by OS (", hex(p), ") not in usable range [", hex(h.arena_start), ",", hex(top), ")\n") sysFree(unsafe.Pointer(p), p_size, &memstats.heap_sys) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index cdb36cd65145bd..e01926e71a59a0 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -156,7 +156,7 @@ func (h *mheap) mapBits(arena_used uintptr) { return } - sysMap(unsafe.Pointer(h.arena_start-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys) + sysMap(unsafe.Pointer(h.bitmap-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys) h.bitmap_mapped = n } @@ -364,7 +364,7 @@ func (m *markBits) advance() { func heapBitsForAddr(addr uintptr) heapBits { // 2 bits per work, 4 pairs per byte, and a mask is hard coded. off := (addr - mheap_.arena_start) / sys.PtrSize - return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/4 - 1)), uint32(off & 3)} + return heapBits{(*uint8)(unsafe.Pointer(mheap_.bitmap - off/4 - 1)), uint32(off & 3)} } // heapBitsForSpan returns the heapBits for the span base address base. diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 1f732c2111c975..46b7048c4092da 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -46,7 +46,7 @@ type mheap struct { nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize) // range of addresses we might see in the heap - bitmap uintptr + bitmap uintptr // Points to one byte past the end of the bitmap bitmap_mapped uintptr arena_start uintptr arena_used uintptr // always mHeap_Map{Bits,Spans} before updating @@ -268,6 +268,28 @@ func inheap(b uintptr) bool { return true } +// inHeapOrStack is a variant of inheap that returns true for pointers into stack spans. +//go:nowritebarrier +//go:nosplit +func inHeapOrStack(b uintptr) bool { + if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used { + return false + } + // Not a beginning of a block, consult span table to find the block beginning. + s := h_spans[(b-mheap_.arena_start)>>_PageShift] + if s == nil || b < s.base() { + return false + } + switch s.state { + case mSpanInUse: + return b < s.limit + case _MSpanStack: + return b < s.base()+s.npages<<_PageShift + default: + return false + } +} + // TODO: spanOf and spanOfUnchecked are open-coded in a lot of places. // Use the functions instead. From 9d7c9b4384db01afd2acb27d3a4636b60e957f08 Mon Sep 17 00:00:00 2001 From: Tal Shprecher Date: Thu, 5 May 2016 15:14:08 -0700 Subject: [PATCH 033/267] cmd/compile: properly handle map assignments for OAS2DOTTYPE The boolean destination in an OAS2DOTTYPE expression craps out during compilation when trying to assign to a map entry because, unlike slice entries, map entries are not directly addressable in memory. The solution is to properly order the boolean destination node so that map entries are set via autotmp variables. Fixes #14678 Change-Id: If344e8f232b5bdac1b53c0f0d21eeb43ab17d3de Reviewed-on: https://go-review.googlesource.com/22833 Reviewed-by: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/order.go | 26 ++++++++++++++++---------- test/fixedbugs/issue14678.go | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 test/fixedbugs/issue14678.go diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 7026ad79efa383..d432b43460b88f 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -569,18 +569,24 @@ func orderstmt(n *Node, order *Order) { orderexprlist(n.List, order) n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T) - if isblank(n.List.First()) { - order.out = append(order.out, n) - } else { - typ := n.Rlist.First().Type - tmp1 := ordertemp(typ, order, haspointers(typ)) - order.out = append(order.out, n) - r := Nod(OAS, n.List.First(), tmp1) - r = typecheck(r, Etop) - ordermapassign(r, order) - n.List.Set([]*Node{tmp1, n.List.Second()}) + + results := n.List.Slice() + var assigns [2]*Node + + for r, res := range results { + if !isblank(res) { + results[r] = ordertemp(res.Type, order, haspointers(res.Type)) + assigns[r] = Nod(OAS, res, results[r]) + } } + order.out = append(order.out, n) + for _, assign := range assigns { + if assign != nil { + assign = typecheck(assign, Etop) + ordermapassign(assign, order) + } + } cleantemp(t, order) // Special: use temporary variables to hold result, diff --git a/test/fixedbugs/issue14678.go b/test/fixedbugs/issue14678.go new file mode 100644 index 00000000000000..94ca86d26ce060 --- /dev/null +++ b/test/fixedbugs/issue14678.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + m := make(map[int]bool) + i := interface{}(1) + var v int + + // Ensure map is updated properly + _, m[1] = i.(int) + v, m[2] = i.(int) + + if v != 1 { + panic("fail: v should be 1") + } + if m[1] == false { + panic("fail: m[1] should be true") + } + if m[2] == false { + panic("fail: m[2] should be true") + } +} From fa270ad98e77cd0625c97eb01ad01efe11a324e8 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 7 May 2016 07:24:39 +0200 Subject: [PATCH 034/267] cmd/go: add -shared to darwin/arm{,64} default build mode Buildmode c-archive now supports position independent code for darwin/arm (in addition to darwin/arm64). Make PIC (-shared) the default for both platforms in the default buildmode. Without this change, gomobile will go install the standard library into its separate package directory without PIC support. Also add -shared to darwin/arm64 in buildmode c-archive, for symmetry (darwin/arm64 always generates position independent code). Fixes #15519 Change-Id: If27d2cbea8f40982e14df25da2703cbba572b5c6 Reviewed-on: https://go-review.googlesource.com/22920 Reviewed-by: David Crawshaw Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- misc/cgo/testcarchive/carchive_test.go | 2 +- src/cmd/go/build.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go index 0174e310156928..ab14c007a9cb52 100644 --- a/misc/cgo/testcarchive/carchive_test.go +++ b/misc/cgo/testcarchive/carchive_test.go @@ -84,7 +84,7 @@ func init() { cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) } libgodir = GOOS + "_" + GOARCH - if GOOS == "darwin" && GOARCH == "arm" { + if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") { libgodir = GOOS + "_" + GOARCH + "_shared" } cc = append(cc, "-I", filepath.Join("pkg", libgodir)) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 6bef09b66b86bf..e0cb216b8c4e56 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -335,7 +335,7 @@ func buildModeInit() { return p } switch platform { - case "darwin/arm": + case "darwin/arm", "darwin/arm64": codegenArg = "-shared" default: } @@ -361,6 +361,9 @@ func buildModeInit() { case "android/arm", "android/arm64", "android/amd64", "android/386": codegenArg = "-shared" ldBuildmode = "pie" + case "darwin/arm", "darwin/arm64": + codegenArg = "-shared" + fallthrough default: ldBuildmode = "exe" } From 394ac818b037ab8a3714b8a23e06e17a1e05aace Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 5 May 2016 18:03:59 -0700 Subject: [PATCH 035/267] cmd/compile: add and enable (internal) option to only track named types The new export format keeps track of all types that are exported. If a type is seen that was exported before, only a reference to that type is emitted. The importer maintains a list of all the seen types and uses that list to resolve type references. The existing compiler infrastructure's invariants assumes that only named types are referred to before they are fully set up. Referring to unnamed incomplete types causes problems. One of the issues was #15548. Added a new internal flag 'trackAllTypes' to enable/disable this type tracking. With this change only named types are tracked. Verified that this fix also addresses #15548, even w/o the prior fix for that issue (in fact that prior fix is turned off if trackAllTypes is disabled because it's not needed). The test for #15548 covers also this change. For #15548. Change-Id: Id0b3ff983629703d025a442823f99649fd728a56 Reviewed-on: https://go-review.googlesource.com/22839 TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/bexport.go | 36 +++- src/cmd/compile/internal/gc/bimport.go | 23 +- src/cmd/compile/internal/gc/builtin.go | 204 +++++++++--------- src/go/internal/gcimporter/bimport.go | 56 +++-- src/go/internal/gcimporter/gcimporter_test.go | 4 +- test/fixedbugs/bug398.go | 15 +- 6 files changed, 205 insertions(+), 133 deletions(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 5d037ae05e74d1..aa1915bb6f2e03 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -125,6 +125,17 @@ const exportVersion = "v0" // Leave for debugging. const exportInlined = true // default: true +// trackAllTypes enables cycle tracking for all types, not just named +// types. The existing compiler invariants assume that unnamed types +// that are not completely set up are not used, or else there are spurious +// errors. +// If disabled, only named types are tracked, possibly leading to slightly +// less efficient encoding in rare cases. It also prevents the export of +// some corner-case type declarations (but those are not handled correctly +// with with the textual export format either). +// TODO(gri) enable and remove once issues caused by it are fixed +const trackAllTypes = false + type exporter struct { out *bufio.Writer @@ -159,6 +170,10 @@ func export(out *bufio.Writer, trace bool) int { trace: trace, } + // TODO(gri) clean up the ad-hoc encoding of the file format below + // (we need this so we can read the builtin package export data + // easily w/o being affected by format changes) + // first byte indicates low-level encoding format var format byte = 'c' // compact if debugFormat { @@ -166,6 +181,12 @@ func export(out *bufio.Writer, trace bool) int { } p.rawByte(format) + format = 'n' // track named types only + if trackAllTypes { + format = 'a' + } + p.rawByte(format) + // posInfo exported or not? p.bool(p.posInfoFormat) @@ -585,14 +606,21 @@ func (p *exporter) typ(t *Type) { } // otherwise, remember the type, write the type tag (< 0) and type data - if p.trace { - p.tracef("T%d = {>\n", len(p.typIndex)) - defer p.tracef("<\n} ") + if trackAllTypes { + if p.trace { + p.tracef("T%d = {>\n", len(p.typIndex)) + defer p.tracef("<\n} ") + } + p.typIndex[t] = len(p.typIndex) } - p.typIndex[t] = len(p.typIndex) // pick off named types if tsym := t.Sym; tsym != nil { + if !trackAllTypes { + // if we don't track all types, track named types now + p.typIndex[t] = len(p.typIndex) + } + // Predeclared types should have been found in the type map. if t.Orig == t { Fatalf("exporter: predeclared type missing from type map?") diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index 6b0593cd472fc4..c4e6e5dd578afe 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -24,10 +24,11 @@ type importer struct { buf []byte // reused for reading strings // object lists, in order of deserialization - strList []string - pkgList []*Pkg - typList []*Type - funcList []*Node // nil entry means already declared + strList []string + pkgList []*Pkg + typList []*Type + funcList []*Node // nil entry means already declared + trackAllTypes bool // for delayed type verification cmpList []struct{ pt, t *Type } @@ -59,6 +60,8 @@ func Import(in *bufio.Reader) { Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format) } + p.trackAllTypes = p.rawByte() == 'a' + p.posInfoFormat = p.bool() // --- generic export data --- @@ -331,7 +334,9 @@ func (p *importer) pos() { func (p *importer) newtyp(etype EType) *Type { t := typ(etype) - p.typList = append(p.typList, t) + if p.trackAllTypes { + p.typList = append(p.typList, t) + } return t } @@ -389,7 +394,13 @@ func (p *importer) typ() *Type { // read underlying type // parser.go:hidden_type t0 := p.typ() - p.importtype(t, t0) // parser.go:hidden_import + if p.trackAllTypes { + // If we track all types, we cannot check equality of previously + // imported types until later. Use customized version of importtype. + p.importtype(t, t0) + } else { + importtype(t, t0) + } // interfaces don't have associated methods if t0.IsInterface() { diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index cc64e73f25c1e3..b9010f4366dcce 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -3,106 +3,108 @@ package gc const runtimeimport = "" + - "c\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00\x01" + - "\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15panic" + - "divide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00\t" + - "\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11gor" + - "ecover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13printf" + - "loat\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00\t" + - "\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15prin" + - "tstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printif" + - "ace\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01:" + - "\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00\x00" + - "\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 \x00" + - " \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19co" + - "ncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstr" + - "ing5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings\x00" + - "\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstri" + - "ng\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!slic" + - "ebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebytetos" + - "tringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f@" + - "\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11\"" + - "\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!stringt" + - "oslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03 " + - "\x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S\r" + - "retv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00\x00" + - "\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestring" + - "copy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00\x02" + - ":\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:l" + - "\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00>p\x00\x00>\vbuf·4\x00\x00\x02:l\x00\x00\t\rc" + - "onvT2I\x00\x06\x17\"\vtab·2\x00\x00>p\x00\x00>t\x00\x00\x02:l\x00\x00\t\x11assert" + - "E2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00>\vret·3\x00\x00\x00\t" + - "\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00>\vret·4\x00\x00" + - "\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assert" + - "E2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertE2T\x00\x06\x17\"|" + - "|\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01" + - "\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13asse" + - "rtI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2I\x00\x06\x17" + - "\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertI2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>" + - "\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13as" + - "sertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x17panicdotty" + - "pe\x00\x06\x17\"\rhave·1\x00\x00\x9a\x01\rwant·2\x00\x00\x9a\x01\x84\x01\x00\x00\x00\t\rifa" + - "ceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04" + - ":\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakemap\x00\b\x17\"\x13mapType·2\x00" + - "\x00\n\rhint·3\x00\x00>\x11mapbuf·4\x00\x00>\x17bucketbuf·5\x00" + - "\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapaccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rh" + - "map·3\x00\x00>\vkey·4\x00\x00\x02>\vval·1\x00\x00\t!mapaccess" + - "1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t!mapa" + - "ccess1_fast64\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t" + - "#mapaccess1_faststr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02" + - ">\xbc\x01\x00\x00\t\x1bmapaccess1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00>\xba\x01\x00" + - "\x00\x17\"\rzero·5\x00\x00\x02>\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapT" + - "ype·3\x00\x00\x1d::\rhmap·4\x00\x00>\vkey·5\x00\x00\x04>\xbc\x01\x00\x00\x00\rp" + - "res·2\x00\x00\t!mapaccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01" + - "\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17" + - "\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2" + - "_faststr\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t" + - "\x1bmapaccess2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00>\xce\x01\x00\x00\x17\"\rze" + - "ro·6\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapTy" + - "pe·1\x00\x00\x1d::\rhmap·2\x00\x00>\vkey·3\x00\x00>\vval·4\x00\x00" + - "\x00\t\x15mapiterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\x0fhiter·3\x00" + - "\x00\x00\t\x11mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\xe2\x01\x00\x00\x00\t\x15mapi" + - "ternext\x00\x02>\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15cha" + - "nType·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv" + - "1\x00\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00>p\x00\x00\x00\t\x11" + - "chanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00>\relem·4" + - "\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00>p\x00\x00\x00\t\x11cl" + - "osechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renabled" + - "\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04>" + - "\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"||" + - "\x00\x00>\vdst·2\x00\x00>\vsrc·3\x00\x00\x00\t\x1btypedslicecopy\x00" + - "\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selectnbs" + - "end\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x01\x00\x00\t\x17selectnbrecv" + - "\x00\x06\x17\"\xf2\x01\x00\x00>p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19selectnbr" + - "ecv2\x00\b\x17\"\xf2\x01\x00\x00>p\x00\x00\x17\x00\x15received·4\x00\x00\x1f\x02:\x0fhcha" + - "n·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00\n\x13selsi" + - "ze·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06\x17\"\vsel\xc2" + - "\xb72\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00\t\x13select" + - "recv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x15selectre" + - "cv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\xf8\x01\x15received·5\x00\x00\x02" + - "\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x0fsele" + - "ctgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makeslice\x00\x06\x17\"\b\x00" + - "\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·1\x00\x00\t\x11grows" + - "lice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:\xcc\x02\x00\x00\t\rmemm" + - "ove\x00\x06>\tto·1\x00\x00>\vfrm·2\x00\x00\x16\x11length·3\x00d\x00\t\v" + - "memclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length·2\x00d\x00\t\x0fmemeq" + - "ual\x00\x06>\ax·2\x00\x00>\ay·3\x00\x00\x16\rsize·4\x00d\x01\x00\x00\t\x11mem" + - "equal8\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal16\x00\x04>\xe2\x02\x00\x00" + - ">\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13mem" + - "equal64\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x15memequal128\x00\x04>\xe2\x02" + - "\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x0fint64div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div" + - "\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00" + - "\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat64toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64" + - "touint64\x00\x01\x1a\x00\x01\x14\x00\t\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1d" + - "uint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e" + - "\vnum·2\x00\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefunc" + - "enter\x00\x01\x16d\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16" + - "d\x00\t\x11racewrite\x00\x01\x16d\x00\t\x19racereadrange\x00\x04\x16\radd" + - "r·1\x00d\x16\rsize·2\x00d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00" + - "d\x16\x96\x03\x00d\x00\t\x0fmsanread\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrit" + - "e\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4\x01\x02\v\x00\x01\x00\n$$\n" + "cn\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" + + "\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" + + "cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" + + "\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" + + "recover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13print" + + "float\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00" + + "\t\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15pri" + + "ntstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printi" + + "face\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01" + + ":\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00" + + "\x00\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 " + + "\x00 \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19c" + + "oncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatst" + + "ring5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings" + + "\x00\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstr" + + "ing\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!sli" + + "cebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebyteto" + + "stringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f" + + "@\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11" + + "\"\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!string" + + "toslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03" + + " \x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S" + + "\rretv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00" + + "\x00\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestrin" + + "gcopy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00" + + "\x02:\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:" + + "l\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00\x17:p\x00\x00\x17:\vbuf·4\x00\x00\x02:l\x00\x00" + + "\t\rconvT2I\x00\x06\x17\"\vtab·2\x00\x00\x17:p\x00\x00\x17:t\x00\x00\x02:l\x00\x00\t\x11a" + + "ssertE2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00\x17:\vret\xc2" + + "\xb73\x00\x00\x00\t\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00\x17:\vr" + + "et·4\x00\x00\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00" + + "\t\x13assertE2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11asser" + + "tE2T\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b" + + "\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00\x17" + + ":\x80\x01\x00\x00\x00\t\x13assertI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t" + + "\x11assertI2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2I" + + "2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00" + + "\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01" + + "\x00\x00\x01\x00\x00\t\x17panicdottype\x00\x06\x17\"\rhave·1\x00\x00\x17\"\rwant" + + "·2\x00\x00\x17\"\x84\x01\x00\x00\x00\t\rifaceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00" + + "\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04:\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakema" + + "p\x00\b\x17\"\x13mapType·2\x00\x00\n\rhint·3\x00\x00\x17:\x11mapbuf·" + + "4\x00\x00\x17:\x17bucketbuf·5\x00\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapa" + + "ccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rhmap·3\x00\x00\x17:\vkey·4\x00\x00\x02\x17" + + ":\vval·1\x00\x00\t!mapaccess1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::" + + "\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t!mapaccess1_fast64\x00\x06\x17\"\xac" + + "\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t#mapaccess1_fasts" + + "tr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t\x1bmapaccess" + + "1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00\x17:\xba\x01\x00\x00\x17\"\rzero·5\x00\x00\x02\x17" + + ":\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapType·3\x00\x00\x1d::\rhm" + + "ap·4\x00\x00\x17:\vkey·5\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\rpres·2\x00\x00\t!ma" + + "paccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01" + + "\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00" + + "\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2_faststr\x00\x06" + + "\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x1bmapacces" + + "s2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00\x17:\xce\x01\x00\x00\x17\"\rzero·6\x00\x00\x04" + + "\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapType·1\x00\x00" + + "\x1d::\rhmap·2\x00\x00\x17:\vkey·3\x00\x00\x17:\vval·4\x00\x00\x00\t\x15ma" + + "piterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\x0fhiter·3\x00\x00\x00\t\x11" + + "mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\xe2\x01\x00\x00\x00\t\x15mapiter" + + "next\x00\x02\x17:\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15chanT" + + "ype·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv1\x00" + + "\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00\x17:p\x00\x00\x00\t\x11c" + + "hanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00\x17:\relem·4" + + "\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00\x17:p\x00\x00\x00\t\x11c" + + "losechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renable" + + "d\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04" + + "\x17:\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"" + + "||\x00\x00\x17:\vdst·2\x00\x00\x17:\vsrc·3\x00\x00\x00\t\x1btypedslicec" + + "opy\x00\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selec" + + "tnbsend\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x01\x00\x00\t\x17selectn" + + "brecv\x00\x06\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19sel" + + "ectnbrecv2\x00\b\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x17\x00\x15received·4\x00\x00\x1f" + + "\x02:\x0fhchan·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00" + + "\n\x13selsize·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06" + + "\x17\"\vsel·2\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00" + + "\t\x13selectrecv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t" + + "\x15selectrecv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x17\x00\x15rece" + + "ived·5\x00\x00\x02\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00" + + "\xb8\x02\x00\x00\t\x0fselectgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makes" + + "lice\x00\x06\x17\"\b\x00\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·" + + "1\x00\x00\t\x11growslice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:" + + "\xcc\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11le" + + "ngth·3\x00d\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length\xc2" + + "\xb72\x00d\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsiz" + + "e·4\x00d\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13m" + + "emequal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04" + + "\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00" + + "\x00\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint6" + + "4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" + + "mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" + + "4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" + + "\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" + + "\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" + + "3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" + + "funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" + + "d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" + + "d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x0fmsanrea" + + "d\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4" + + "\x01\x02\v\x00\x01\x00\n$$\n" const unsafeimport = "" + - "c\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01:" + - "\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v\x00" + - "\x01\x00\n$$\n" + "cn\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" + + ":\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v" + + "\x00\x01\x00\n$$\n" diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index eb29df77ab757b..964bf5512e080c 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -23,9 +23,10 @@ type importer struct { buf []byte // for reading strings // object lists - strList []string // in order of appearance - pkgList []*types.Package // in order of appearance - typList []types.Type // in order of appearance + strList []string // in order of appearance + pkgList []*types.Package // in order of appearance + typList []types.Type // in order of appearance + trackAllTypes bool // position encoding posInfoFormat bool @@ -59,6 +60,8 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) } + p.trackAllTypes = p.rawByte() == 'a' + p.posInfoFormat = p.int() != 0 // --- generic export data --- @@ -93,7 +96,12 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i // complete interfaces for _, typ := range p.typList { - if it, ok := typ.(*types.Interface); ok { + // If we only record named types (!p.trackAllTypes), + // we must check the underlying types here. If we + // track all types, the Underlying() method call is + // not needed. + // TODO(gri) Remove if p.trackAllTypes is gone. + if it, ok := typ.Underlying().(*types.Interface); ok { it.Complete() } } @@ -304,7 +312,9 @@ func (p *importer) typ(parent *types.Package) types.Type { case arrayTag: t := new(types.Array) - p.record(t) + if p.trackAllTypes { + p.record(t) + } n := p.int64() *t = *types.NewArray(p.typ(parent), n) @@ -312,35 +322,45 @@ func (p *importer) typ(parent *types.Package) types.Type { case sliceTag: t := new(types.Slice) - p.record(t) + if p.trackAllTypes { + p.record(t) + } *t = *types.NewSlice(p.typ(parent)) return t case dddTag: t := new(dddSlice) - p.record(t) + if p.trackAllTypes { + p.record(t) + } t.elem = p.typ(parent) return t case structTag: t := new(types.Struct) - p.record(t) + if p.trackAllTypes { + p.record(t) + } *t = *types.NewStruct(p.fieldList(parent)) return t case pointerTag: t := new(types.Pointer) - p.record(t) + if p.trackAllTypes { + p.record(t) + } *t = *types.NewPointer(p.typ(parent)) return t case signatureTag: t := new(types.Signature) - p.record(t) + if p.trackAllTypes { + p.record(t) + } params, isddd := p.paramList() result, _ := p.paramList() @@ -353,7 +373,9 @@ func (p *importer) typ(parent *types.Package) types.Type { // such cycle must contain a named type which would have been // first defined earlier. n := len(p.typList) - p.record(nil) + if p.trackAllTypes { + p.record(nil) + } // no embedded interfaces with gc compiler if p.int() != 0 { @@ -361,12 +383,16 @@ func (p *importer) typ(parent *types.Package) types.Type { } t := types.NewInterface(p.methodList(parent), nil) - p.typList[n] = t + if p.trackAllTypes { + p.typList[n] = t + } return t case mapTag: t := new(types.Map) - p.record(t) + if p.trackAllTypes { + p.record(t) + } key := p.typ(parent) val := p.typ(parent) @@ -375,7 +401,9 @@ func (p *importer) typ(parent *types.Package) types.Type { case chanTag: t := new(types.Chan) - p.record(t) + if p.trackAllTypes { + p.record(t) + } var dir types.ChanDir // tag values must match the constants in cmd/compile/internal/gc/go.go diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index e56720b0d52543..8b94f9a105a6c1 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -351,9 +351,9 @@ func TestIssue13898(t *testing.T) { } // lookup go/types.Object.Pkg method - m, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Pkg") + m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg") if m == nil { - t.Fatal("go/types.Object.Pkg not found") + t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect) } // the method must belong to go/types diff --git a/test/fixedbugs/bug398.go b/test/fixedbugs/bug398.go index a80a960394470b..81bf33c37a6df1 100644 --- a/test/fixedbugs/bug398.go +++ b/test/fixedbugs/bug398.go @@ -8,17 +8,20 @@ package p -type I1 interface { - F() interface{I1} +type i1 interface { + F() interface{i1} } -type I2 interface { - F() interface{I2} +type i2 interface { + F() interface{i2} } -var v1 I1 -var v2 I2 +var v1 i1 +var v2 i2 func f() bool { return v1 == v2 } + +// TODO(gri) Change test to use exported interfaces. +// See issue #15596 for details. \ No newline at end of file From 0b6e5e3d733c1da53244753b42940eddb7401c6c Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sun, 8 May 2016 01:27:45 +1000 Subject: [PATCH 036/267] cmd/link: specify correct size for dynamic symbols in 386 elf output Currently 386 ELF binaries are generated with dynamic symbols that have a size of zero bytes, even though the symbol in the symbol table has the correct size. Fix this by specifying the correct size when creating dynamic symbols. Issue found on OpenBSD -current, where ld.so is now producing link warnings due to mismatched symbol sizes. Fixes #15593. Change-Id: Ib1a12b23ff9159c61ac980bf48a983b86f3df256 Reviewed-on: https://go-review.googlesource.com/22912 Reviewed-by: Minux Ma Run-TryBot: Minux Ma TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/elf.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index e66de49f413373..39d3609a291f04 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -2665,8 +2665,8 @@ func Elfadddynsym(ctxt *Link, s *LSym) { Addaddr(ctxt, d, s) } - /* size */ - Adduint32(ctxt, d, 0) + /* size of object */ + Adduint32(ctxt, d, uint32(s.Size)) /* type */ t := STB_GLOBAL << 4 From 55546efeee9fb6104d3dfd76351e7765df0bdd71 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sun, 8 May 2016 12:54:31 -0700 Subject: [PATCH 037/267] Revert "cmd/compile: properly handle map assignments for OAS2DOTTYPE" This reverts commit 9d7c9b4384db01afd2acb27d3a4636b60e957f08. For #15602. Change-Id: I464184b05babe4cb8dedab6161efa730cea6ee2d Reviewed-on: https://go-review.googlesource.com/22930 Run-TryBot: Matthew Dempsky Reviewed-by: Josh Bleecher Snyder TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/order.go | 26 ++++++++++---------------- test/fixedbugs/issue14678.go | 27 --------------------------- 2 files changed, 10 insertions(+), 43 deletions(-) delete mode 100644 test/fixedbugs/issue14678.go diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index d432b43460b88f..7026ad79efa383 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -569,24 +569,18 @@ func orderstmt(n *Node, order *Order) { orderexprlist(n.List, order) n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T) - - results := n.List.Slice() - var assigns [2]*Node - - for r, res := range results { - if !isblank(res) { - results[r] = ordertemp(res.Type, order, haspointers(res.Type)) - assigns[r] = Nod(OAS, res, results[r]) - } + if isblank(n.List.First()) { + order.out = append(order.out, n) + } else { + typ := n.Rlist.First().Type + tmp1 := ordertemp(typ, order, haspointers(typ)) + order.out = append(order.out, n) + r := Nod(OAS, n.List.First(), tmp1) + r = typecheck(r, Etop) + ordermapassign(r, order) + n.List.Set([]*Node{tmp1, n.List.Second()}) } - order.out = append(order.out, n) - for _, assign := range assigns { - if assign != nil { - assign = typecheck(assign, Etop) - ordermapassign(assign, order) - } - } cleantemp(t, order) // Special: use temporary variables to hold result, diff --git a/test/fixedbugs/issue14678.go b/test/fixedbugs/issue14678.go deleted file mode 100644 index 94ca86d26ce060..00000000000000 --- a/test/fixedbugs/issue14678.go +++ /dev/null @@ -1,27 +0,0 @@ -// run - -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func main() { - m := make(map[int]bool) - i := interface{}(1) - var v int - - // Ensure map is updated properly - _, m[1] = i.(int) - v, m[2] = i.(int) - - if v != 1 { - panic("fail: v should be 1") - } - if m[1] == false { - panic("fail: m[1] should be true") - } - if m[2] == false { - panic("fail: m[2] should be true") - } -} From 3696e469e5f8a5531c69ffcf091deaa692e81104 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 8 May 2016 14:32:48 -0700 Subject: [PATCH 038/267] test: add test for issue 15602 The problem was fixed by the rollback in CL 22930. This CL just adds a test to prevent regressions. Fixes #15602 Change-Id: I37453f6e18ca43081266fe7f154c6d63fbaffd9b Reviewed-on: https://go-review.googlesource.com/22931 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- test/fixedbugs/issue15602.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 test/fixedbugs/issue15602.go diff --git a/test/fixedbugs/issue15602.go b/test/fixedbugs/issue15602.go new file mode 100644 index 00000000000000..badf8133c52176 --- /dev/null +++ b/test/fixedbugs/issue15602.go @@ -0,0 +1,11 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f(i interface{}) { + i, _ = i.(error) +} From 87a2ae1fa25677dc9097a25292c54b7b9dac2c9d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sun, 8 May 2016 20:59:53 -0700 Subject: [PATCH 039/267] cmd/compile: fix binary export of composite literals with implicit types Also: - replaced remaining panics with Fatal calls - more comments Fixes #15572. Change-Id: Ifb27e80b66700f5692a84078764a1e928d4b310d Reviewed-on: https://go-review.googlesource.com/22935 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/bexport.go | 43 ++++++++++++++------------ src/cmd/compile/internal/gc/bimport.go | 27 +++++++--------- test/fixedbugs/issue15572.dir/a.go | 40 ++++++++++++++++++++++++ test/fixedbugs/issue15572.dir/b.go | 27 ++++++++++++++++ test/fixedbugs/issue15572.go | 11 +++++++ 5 files changed, 113 insertions(+), 35 deletions(-) create mode 100644 test/fixedbugs/issue15572.dir/a.go create mode 100644 test/fixedbugs/issue15572.dir/b.go create mode 100644 test/fixedbugs/issue15572.go diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index aa1915bb6f2e03..cd2963e8e64e09 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -937,7 +937,7 @@ func parName(f *Field, numbered bool) string { // print symbol with Vargen number or not as desired name := s.Name if strings.Contains(name, ".") { - panic("invalid symbol name: " + name) + Fatalf("invalid symbol name: %s", name) } // Functions that can be inlined use numbered parameters so we can distingish them @@ -1040,6 +1040,8 @@ func (p *exporter) float(x *Mpflt) { // but instead of emitting the information textually, emit the node tree in // binary form. +// TODO(gri) Improve tracing output. The current format is difficult to read. + // stmtList may emit more (or fewer) than len(list) nodes. func (p *exporter) stmtList(list Nodes) { if p.trace { @@ -1116,6 +1118,16 @@ func (p *exporter) expr(n *Node) { defer p.tracef(") ") } + // from nodefmt (fmt.go) + // + // nodefmt reverts nodes back to their original - we don't need to do + // it because we are not bound to produce valid Go syntax when exporting + // + // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { + // n = n.Orig + // } + + // from exprfmt (fmt.go) for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) { n = n.Left } @@ -1188,14 +1200,14 @@ func (p *exporter) expr(n *Node) { p.typ(n.Type) } - case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: - panic("unreachable") // should have been resolved by typechecking + // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: + // should have been resolved by typechecking - handled by default case // case OCLOSURE: // unimplemented - handled by default case // case OCOMPLIT: - // unimplemented - handled by default case + // should have been resolved by typechecking - handled by default case case OPTRLIT: p.op(OPTRLIT) @@ -1204,16 +1216,12 @@ func (p *exporter) expr(n *Node) { case OSTRUCTLIT: p.op(OSTRUCTLIT) - if !p.bool(n.Implicit) { - p.typ(n.Type) - } + p.typ(n.Type) p.elemList(n.List) // special handling of field names case OARRAYLIT, OMAPLIT: - p.op(op) - if !p.bool(n.Implicit) { - p.typ(n.Type) - } + p.op(OCOMPLIT) + p.typ(n.Type) p.exprList(n.List) case OKEY: @@ -1226,9 +1234,6 @@ func (p *exporter) expr(n *Node) { case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: p.op(OXDOT) p.expr(n.Left) - if n.Sym == nil { - panic("unreachable") // can this happen during export? - } p.fieldSym(n.Sym, true) case ODOTTYPE, ODOTTYPE2: @@ -1334,7 +1339,8 @@ func (p *exporter) expr(n *Node) { p.op(ODCLCONST) default: - Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op) + Fatalf("cannot export %s (%d) node\n"+ + "==> please file an issue and assign to gri@\n", n.Op, n.Op) } } @@ -1410,9 +1416,8 @@ func (p *exporter) stmt(n *Node) { p.op(ORETURN) p.exprList(n.List) - case ORETJMP: - // generated by compiler for trampolin routines - not exported - panic("unreachable") + // case ORETJMP: + // unreachable - generated by compiler for trampolin routines case OPROC, ODEFER: p.op(op) @@ -1457,7 +1462,7 @@ func (p *exporter) stmt(n *Node) { p.exprsOrNil(n.Left, nil) case OEMPTY: - // nothing to emit + // nothing to emit case OLABEL: p.op(OLABEL) diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index c4e6e5dd578afe..cb375a0ac3fd5b 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -233,7 +233,7 @@ func (p *importer) pkg() *Pkg { // an empty path denotes the package we are currently importing; // it must be the first package we see if (path == "") != (len(p.pkgList) == 0) { - panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList))) + Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList)) } pkg := importpkg @@ -821,12 +821,9 @@ func (p *importer) node() *Node { // case OCLOSURE: // unimplemented - // case OCOMPLIT: - // unimplemented - case OPTRLIT: n := p.expr() - if !p.bool() /* !implicit, i.e. '&' operator*/ { + if !p.bool() /* !implicit, i.e. '&' operator */ { if n.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. n.Right = Nod(OIND, n.Right, nil) @@ -838,18 +835,15 @@ func (p *importer) node() *Node { return n case OSTRUCTLIT: - n := Nod(OCOMPLIT, nil, nil) - if !p.bool() { - n.Right = typenod(p.typ()) - } - n.List.Set(p.elemList()) + n := Nod(OCOMPLIT, nil, typenod(p.typ())) + n.List.Set(p.elemList()) // special handling of field names return n - case OARRAYLIT, OMAPLIT: - n := Nod(OCOMPLIT, nil, nil) - if !p.bool() { - n.Right = typenod(p.typ()) - } + // case OARRAYLIT, OMAPLIT: + // unreachable - mapped to case OCOMPLIT below by exporter + + case OCOMPLIT: + n := Nod(OCOMPLIT, nil, typenod(p.typ())) n.List.Set(p.exprList()) return n @@ -1090,7 +1084,8 @@ func (p *importer) node() *Node { return nil default: - Fatalf("importer: %s (%d) node not yet supported", op, op) + Fatalf("cannot import %s (%d) node\n"+ + "==> please file an issue and assign to gri@\n", op, op) panic("unreachable") // satisfy compiler } } diff --git a/test/fixedbugs/issue15572.dir/a.go b/test/fixedbugs/issue15572.dir/a.go new file mode 100644 index 00000000000000..13566014304714 --- /dev/null +++ b/test/fixedbugs/issue15572.dir/a.go @@ -0,0 +1,40 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T struct { +} + +func F() []T { + return []T{T{}} +} + +func Fi() []T { + return []T{{}} // element with implicit composite literal type +} + +func Fp() []*T { + return []*T{&T{}} +} + +func Fip() []*T { + return []*T{{}} // element with implicit composite literal type +} + +func Gp() map[int]*T { + return map[int]*T{0: &T{}} +} + +func Gip() map[int]*T { + return map[int]*T{0: {}} // element with implicit composite literal type +} + +func Hp() map[*T]int { + return map[*T]int{&T{}: 0} +} + +func Hip() map[*T]int { + return map[*T]int{{}: 0} // key with implicit composite literal type +} diff --git a/test/fixedbugs/issue15572.dir/b.go b/test/fixedbugs/issue15572.dir/b.go new file mode 100644 index 00000000000000..355accc88057bd --- /dev/null +++ b/test/fixedbugs/issue15572.dir/b.go @@ -0,0 +1,27 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func F() { + a.F() + a.Fi() +} + +func Fp() { + a.Fp() + a.Fip() +} + +func Gp() { + a.Gp() + a.Gip() +} + +func Hp() { + a.Hp() + a.Hip() +} diff --git a/test/fixedbugs/issue15572.go b/test/fixedbugs/issue15572.go new file mode 100644 index 00000000000000..cf77778f6640ff --- /dev/null +++ b/test/fixedbugs/issue15572.go @@ -0,0 +1,11 @@ +// compiledir + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that exporting composite literals with implicit +// types doesn't crash the typechecker when running over +// inlined function bodies containing such literals. + +package ignored From aeecee8ce4cf1821dcb6b5e37e20f40696278498 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 9 May 2016 15:11:24 +0200 Subject: [PATCH 040/267] runtime/race: deflake test The test sometimes fails on builders. The test uses sleeps to establish the necessary goroutine execution order. If sleeps undersleep/oversleep the race is still reported, but it can be reported when the main test goroutine returns. In such case test driver can't match the race with the test and reports failure. Wait for both test goroutines to ensure that the race is reported in the test scope. Fixes #15579 Change-Id: I0b9bec0ebfb0c127d83eb5325a7fe19ef9545050 Reviewed-on: https://go-review.googlesource.com/22951 Run-TryBot: Dmitry Vyukov TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/race/testdata/chan_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/runtime/race/testdata/chan_test.go b/src/runtime/race/testdata/chan_test.go index cddd9a6e782f2a..449191639e6180 100644 --- a/src/runtime/race/testdata/chan_test.go +++ b/src/runtime/race/testdata/chan_test.go @@ -285,17 +285,20 @@ func TestRaceChanWrongClose(t *testing.T) { v1 := 0 v2 := 0 c := make(chan int, 1) + done := make(chan bool) go func() { defer func() { recover() }() v1 = 1 c <- 1 + done <- true }() go func() { time.Sleep(1e7) v2 = 2 close(c) + done <- true }() time.Sleep(2e7) if _, who := <-c; who { @@ -303,6 +306,8 @@ func TestRaceChanWrongClose(t *testing.T) { } else { v1 = 2 } + <-done + <-done } func TestRaceChanSendClose(t *testing.T) { From feb6131b1a4c0da098821c516e06499add886182 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 26 Apr 2016 21:50:59 -0400 Subject: [PATCH 041/267] cmd/compile: add -linkobj flag to allow writing object file in two parts This flag is experimental and the semantics may change even after Go 1.7 is released. There are no changes to code not using the flag. The first part is for reading by future compiles. The second part is for reading by the final link step. Splitting the file this way allows distributed build systems to ship the compile-input part only to compile steps and the linker-input part only to linker steps. The first part is basically just the export data, and the second part is basically everything else. The overall files still have the same broad structure, so that existing tools will work with both halves. It's just that various pieces are empty in the two halves. This also copies the two bits of data the linker needed from export data into the object header proper, so that the linker doesn't need any export data at all. That eliminates a TODO that was left for switching to the binary export data. (Now the linker doesn't need to know about the switch.) The default is still to write out a combined output file. Nothing changes unless you pass -linkobj to the compiler. There is no support in the go command for -linkobj, since the go command doesn't copy objects around. The expectation is that other build systems (like bazel, say) might take advantage of this. The header adjustment and the option for the split output was intended as part of the zip archives, but the zip archives have been cut from Go 1.7. Doing this to the current archives both unblocks one step in the switch to binary export data and enables alternate build systems to experiment with the new flag using the Go 1.7 release. Change-Id: I8b6eab25b8a22b0a266ba0ac6d31e594f3d117f3 Reviewed-on: https://go-review.googlesource.com/22500 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer --- src/cmd/compile/doc.go | 7 +- src/cmd/compile/internal/gc/go.go | 1 + src/cmd/compile/internal/gc/main.go | 3 +- src/cmd/compile/internal/gc/obj.go | 62 ++++++++++- src/cmd/link/internal/ld/go.go | 82 ++++----------- src/debug/gosym/pclntab_test.go | 16 +++ test/linkobj.go | 155 ++++++++++++++++++++++++++++ 7 files changed, 260 insertions(+), 66 deletions(-) create mode 100644 test/linkobj.go diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index 2b45e5b998bc10..6783c2e846a3d5 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -61,7 +61,12 @@ Flags: Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix instead of $GOROOT/pkg/$GOOS_$GOARCH. -largemodel - Generated code that assumes a large memory model. + Generate code that assumes a large memory model. + -linkobj file + Write linker-specific object to file and compiler-specific + object to usual output file (as specified by -o). + Without this flag, the -o output is a combination of both + linker and compiler input. -memprofile file Write memory profile for the compilation to file. -memprofilerate rate diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index f9a372dccee63d..cbb79c02618a22 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -133,6 +133,7 @@ var pragcgobuf string var infile string var outfile string +var linkobj string var bout *bio.Writer diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 54211e4892ddef..713ff13d8547d8 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -178,6 +178,7 @@ func Main() { flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) obj.Flagcount("l", "disable inlining", &Debug['l']) + flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") obj.Flagcount("live", "debug liveness analysis", &debuglive) obj.Flagcount("m", "print optimization decisions", &Debug['m']) flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") @@ -772,7 +773,7 @@ func importfile(f *Val, indent []byte) { if p != "empty archive" { if !strings.HasPrefix(p, "go object ") { - Yyerror("import %s: not a go object file", file) + Yyerror("import %s: not a go object file: %s", file, p) errorexit() } diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index ae23f9557410a3..b5c06d165d4c6d 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -22,7 +22,34 @@ func formathdr(arhdr []byte, name string, size int64) { copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size)) } +// These modes say which kind of object file to generate. +// The default use of the toolchain is to set both bits, +// generating a combined compiler+linker object, one that +// serves to describe the package to both the compiler and the linker. +// In fact the compiler and linker read nearly disjoint sections of +// that file, though, so in a distributed build setting it can be more +// efficient to split the output into two files, supplying the compiler +// object only to future compilations and the linker object only to +// future links. +// +// By default a combined object is written, but if -linkobj is specified +// on the command line then the default -o output is a compiler object +// and the -linkobj output is a linker object. +const ( + modeCompilerObj = 1 << iota + modeLinkerObj +) + func dumpobj() { + if linkobj == "" { + dumpobj1(outfile, modeCompilerObj|modeLinkerObj) + } else { + dumpobj1(outfile, modeCompilerObj) + dumpobj1(linkobj, modeLinkerObj) + } +} + +func dumpobj1(outfile string, mode int) { var err error bout, err = bio.Create(outfile) if err != nil { @@ -40,8 +67,27 @@ func dumpobj() { startobj = bout.Offset() } - fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) - dumpexport() + printheader := func() { + fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) + if buildid != "" { + fmt.Fprintf(bout, "build id %q\n", buildid) + } + if localpkg.Name == "main" { + fmt.Fprintf(bout, "main\n") + } + if safemode { + fmt.Fprintf(bout, "safe\n") + } else { + fmt.Fprintf(bout, "----\n") // room for some other tool to write "safe" + } + fmt.Fprintf(bout, "\n") // header ends with blank line + } + + printheader() + + if mode&modeCompilerObj != 0 { + dumpexport() + } if writearchive { bout.Flush() @@ -53,12 +99,20 @@ func dumpobj() { formathdr(arhdr[:], "__.PKGDEF", size) bout.Write(arhdr[:]) bout.Flush() - bout.Seek(startobj+size+(size&1), 0) + } + + if mode&modeLinkerObj == 0 { + bout.Close() + return + } + + if writearchive { + // start object file arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) startobj = bout.Offset() - fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) + printheader() } if pragcgobuf != "" { diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 425c75571fee81..79cdae0aee898c 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -59,71 +59,33 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) } data := string(bdata) - // first \n$$ marks beginning of exports - skip rest of line - p0 = strings.Index(data, "\n$$") - if p0 < 0 { - if Debug['u'] != 0 && whence != ArchiveObj { - Exitf("cannot find export data in %s", filename) - } - return - } - - // \n$$B marks the beginning of binary export data - don't skip over the B - p0 += 3 - for p0 < len(data) && data[p0] != '\n' && data[p0] != 'B' { - p0++ - } - - // second marks end of exports / beginning of local data - p1 = strings.Index(data[p0:], "\n$$\n") - if p1 < 0 && whence == Pkgdef { - p1 = len(data) - p0 - } - if p1 < 0 { - fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename) - if Debug['u'] != 0 { - errorexit() - } - return - } - p1 += p0 - - for p0 < p1 && data[p0] != 'B' && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { - p0++ - } - // don't check this section if we have binary (B) export data - // TODO fix this eventually - if p0 < p1 && data[p0] != 'B' { - if !strings.HasPrefix(data[p0:], "package ") { - fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:]) - if Debug['u'] != 0 { - errorexit() - } - return + // process header lines + isSafe := false + isMain := false + for data != "" { + var line string + if i := strings.Index(data, "\n"); i >= 0 { + line, data = data[:i], data[i+1:] + } else { + line, data = data, "" } - - p0 += 8 - for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { - p0++ + if line == "safe" { + isSafe = true } - pname := p0 - for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' { - p0++ + if line == "main" { + isMain = true } - if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) { - Exitf("load of unsafe package %s", filename) + if line == "" { + break } + } - name := data[pname:p0] - for p0 < p1 && data[p0] != '\n' { - p0++ + if whence == Pkgdef || whence == FileObj { + if pkg == "main" && !isMain { + Exitf("%s: not package main", filename) } - if p0 < p1 { - p0++ - } - - if pkg == "main" && name != "main" { - Exitf("%s: not package main (package %s)", filename, name) + if Debug['u'] != 0 && whence != ArchiveObj && !isSafe { + Exitf("load of unsafe package %s", filename) } } @@ -133,7 +95,7 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) } // look for cgo section - p0 = strings.Index(data[p1:], "\n$$ // cgo") + p0 = strings.Index(data, "\n$$ // cgo") if p0 >= 0 { p0 += p1 i := strings.IndexByte(data[p0+1:], '\n') diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go index 1a780bf121ac4c..9f82e31ae4170a 100644 --- a/src/debug/gosym/pclntab_test.go +++ b/src/debug/gosym/pclntab_test.go @@ -5,6 +5,7 @@ package gosym import ( + "bytes" "debug/elf" "internal/testenv" "io/ioutil" @@ -42,6 +43,21 @@ func dotest(t *testing.T) { if err := cmd.Run(); err != nil { t.Fatal(err) } + + // stamp .o file as being 'package main' so that go tool link will accept it + data, err := ioutil.ReadFile(pclinetestBinary + ".o") + if err != nil { + t.Fatal(err) + } + i := bytes.IndexByte(data, '\n') + if i < 0 { + t.Fatal("bad binary") + } + data = append(append(data[:i:i], "\nmain"...), data[i:]...) + if err := ioutil.WriteFile(pclinetestBinary+".o", data, 0666); err != nil { + t.Fatal(err) + } + cmd = exec.Command("go", "tool", "link", "-H", "linux", "-o", pclinetestBinary, pclinetestBinary+".o") cmd.Stdout = os.Stdout diff --git a/test/linkobj.go b/test/linkobj.go new file mode 100644 index 00000000000000..8a86aa872f0362 --- /dev/null +++ b/test/linkobj.go @@ -0,0 +1,155 @@ +// +build !nacl +// run + +// 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. + +// Test the compiler -linkobj flag. + +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "strings" +) + +var pwd, tmpdir string + +func main() { + dir, err := ioutil.TempDir("", "go-test-linkobj-") + if err != nil { + log.Fatal(err) + } + pwd, err = os.Getwd() + if err != nil { + log.Fatal(err) + } + if err := os.Chdir(dir); err != nil { + os.RemoveAll(dir) + log.Fatal(err) + } + tmpdir = dir + + writeFile("p1.go", ` + package p1 + + func F() { + println("hello from p1") + } + `) + writeFile("p2.go", ` + package p2 + + import "./p1" + + func F() { + p1.F() + println("hello from p2") + } + + func main() {} + `) + writeFile("p3.go", ` + package main + + import "./p2" + + func main() { + p2.F() + println("hello from main") + } + `) + + // two rounds: once using normal objects, again using .a files (compile -pack). + for round := 0; round < 2; round++ { + pkg := "-pack=" + fmt.Sprint(round) + + // The compiler expects the files being read to have the right suffix. + o := "o" + if round == 1 { + o = "a" + } + + // inlining is disabled to make sure that the link objects contain needed code. + run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p1."+o, "-linkobj", "p1.lo", "p1.go") + run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p2."+o, "-linkobj", "p2.lo", "p2.go") + run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p3."+o, "-linkobj", "p3.lo", "p3.go") + + cp("p1."+o, "p1.oo") + cp("p2."+o, "p2.oo") + cp("p3."+o, "p3.oo") + cp("p1.lo", "p1."+o) + cp("p2.lo", "p2."+o) + cp("p3.lo", "p3."+o) + out := runFail("go", "tool", "link", "p2."+o) + if !strings.Contains(out, "not package main") { + fatalf("link p2.o failed but not for package main:\n%s", out) + } + + run("go", "tool", "link", "-L", ".", "-o", "a.out.exe", "p3."+o) + out = run("./a.out.exe") + if !strings.Contains(out, "hello from p1\nhello from p2\nhello from main\n") { + fatalf("running main, incorrect output:\n%s", out) + } + + // ensure that mistaken future round can't use these + os.Remove("p1.o") + os.Remove("a.out.exe") + } + + cleanup() +} + +func run(args ...string) string { + out, err := exec.Command(args[0], args[1:]...).CombinedOutput() + if err != nil { + fatalf("run %v: %s\n%s", args, err, out) + } + return string(out) +} + +func runFail(args ...string) string { + out, err := exec.Command(args[0], args[1:]...).CombinedOutput() + if err == nil { + fatalf("runFail %v: unexpected success!\n%s", args, err, out) + } + return string(out) +} + +func cp(src, dst string) { + data, err := ioutil.ReadFile(src) + if err != nil { + fatalf("%v", err) + } + err = ioutil.WriteFile(dst, data, 0666) + if err != nil { + fatalf("%v", err) + } +} + +func writeFile(name, data string) { + err := ioutil.WriteFile(name, []byte(data), 0666) + if err != nil { + fatalf("%v", err) + } +} + +func cleanup() { + const debug = false + if debug { + println("TMPDIR:", tmpdir) + return + } + os.Chdir(pwd) // get out of tmpdir before removing it + os.RemoveAll(tmpdir) +} + +func fatalf(format string, args ...interface{}) { + cleanup() + log.Fatalf(format, args...) +} From 149ac34893ad1cc5023ae2fbabd0d553f21b0313 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Mon, 9 May 2016 19:28:28 +0200 Subject: [PATCH 042/267] doc: update number of supported instruction sets Current number was out-of-date since adding MIPS. Change-Id: I565342a92de3893b75cdfb76fa39f7fdf15672da Reviewed-on: https://go-review.googlesource.com/22952 Reviewed-by: Brad Fitzpatrick --- doc/install-source.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install-source.html b/doc/install-source.html index d9157c2b17c761..9a817676c17bd9 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -33,7 +33,7 @@

Introduction

-The Go compilers support five instruction sets. +The Go compilers support six instruction sets. There are important differences in the quality of the compilers for the different architectures.

From 3c090019172afd4517360606efc50750d3e278fa Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 6 May 2016 17:05:02 -0700 Subject: [PATCH 043/267] cmd/compile: correct sparseSet probes in regalloc to avoid index error In regalloc, a sparse map is preallocated for later use by spill-in-loop sinking. However, variables (spills) are added during register allocation before spill sinking, and a map query involving any of these new variables will index out of bounds in the map. To fix: 1) fix the queries to use s.orig[v.ID].ID instead, to ensure proper indexing. Note that s.orig will be nil for values that are not eligible for spilling (like memory and flags). 2) add a test. Fixes #15585. Change-Id: I8f2caa93b132a0f2a9161d2178320d5550583075 Reviewed-on: https://go-review.googlesource.com/22911 Reviewed-by: Keith Randall Run-TryBot: David Chase TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/ssa/regalloc.go | 15 +++++--- test/fixedbugs/issue15585.go | 45 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 test/fixedbugs/issue15585.go diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 1b12c6f300cee3..6c391aba2994bc 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1311,20 +1311,25 @@ func (s *regAllocState) regalloc(f *Func) { // Start with live at end. for _, li := range s.live[ss.ID] { if s.isLoopSpillCandidate(loop, s.orig[li.ID]) { + // s.live contains original IDs, use s.orig above to map back to *Value entryCandidates.setBit(li.ID, uint(whichExit)) } } // Control can also be live. - if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) { - entryCandidates.setBit(ss.Control.ID, uint(whichExit)) + if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) { + entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit)) } // Walk backwards, filling in locally live values, removing those defined. for i := len(ss.Values) - 1; i >= 0; i-- { v := ss.Values[i] - entryCandidates.remove(v.ID) // Cannot be an issue, only keeps the sets smaller. + vorig := s.orig[v.ID] + if vorig != nil { + entryCandidates.remove(vorig.ID) // Cannot be an issue, only keeps the sets smaller. + } for _, a := range v.Args { - if s.isLoopSpillCandidate(loop, a) { - entryCandidates.setBit(a.ID, uint(whichExit)) + aorig := s.orig[a.ID] + if aorig != nil && s.isLoopSpillCandidate(loop, aorig) { + entryCandidates.setBit(aorig.ID, uint(whichExit)) } } } diff --git a/test/fixedbugs/issue15585.go b/test/fixedbugs/issue15585.go new file mode 100644 index 00000000000000..79eb13f90db45f --- /dev/null +++ b/test/fixedbugs/issue15585.go @@ -0,0 +1,45 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bug + +func example(n int) (rc int) { + var cc, ll, pp, rr [27]int + for q0 := 0; q0 < n-2; q0++ { + for q1 := q0 + 2; q1 < n; q1++ { + var c, d, l, p, r int + b0 := 1 << uint(q0) + b1 := 1 << uint(q1) + l = ((b0 << 1) | b1) << 1 + c = b0 | b1 | (-1 << uint(n)) + r = ((b0 >> 1) | b1) >> 1 + E: + if c != -1 { + p = ^(l | c | r) + } else { + rc++ + goto R + } + L: + if p != 0 { + lsb := p & -p + p &^= lsb + ll[d], cc[d], rr[d], pp[d] = l, c, r, p + l, c, r = (l|lsb)<<1, c|lsb, (r|lsb)>>1 + d++ + goto E + } + R: + d-- + if d >= 0 { + l, c, r, p = ll[d], cc[d], rr[d], pp[d] + goto L + } + } + } + rc <<= 1 + return +} From 5934523e75e2aa3725c4e709be56d9e84c472bfe Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sun, 8 May 2016 22:31:09 -0400 Subject: [PATCH 044/267] cmd/compile: document -l in godoc Fixes #15607. Change-Id: I3e68ad00ebe72027d064238d4e77f1ad6a52f533 Reviewed-on: https://go-review.googlesource.com/22940 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/doc.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index 6783c2e846a3d5..2e77f702e353f5 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -60,6 +60,8 @@ Flags: -installsuffix suffix Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix instead of $GOROOT/pkg/$GOOS_$GOARCH. + -l + Disable inlining. -largemodel Generate code that assumes a large memory model. -linkobj file From 7ba54d45732219af86bde9a5b73c145db82b70c6 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Mon, 28 Mar 2016 02:29:18 -0700 Subject: [PATCH 045/267] compress: update documentation regarding footer verification Address two documentation issues: 1) Document that the GZIP and ZLIB footer is only verified when the reader has been fully consumed. 2) The zlib reader is guaranteed to not read past the EOF if the input io.Reader is also a io.ByteReader. This functionality was documented in the flate and gzip packages but not on zlib. Fixes #14867 Change-Id: I43d46b93e38f98a04901dc7d4f18ed2f9e09f6fb Reviewed-on: https://go-review.googlesource.com/21218 Reviewed-by: Brad Fitzpatrick --- src/compress/gzip/gunzip.go | 2 ++ src/compress/zlib/reader.go | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go index 926bae88c70bda..7e640692f3f265 100644 --- a/src/compress/gzip/gunzip.go +++ b/src/compress/gzip/gunzip.go @@ -282,4 +282,6 @@ func (z *Reader) Read(p []byte) (n int, err error) { } // Close closes the Reader. It does not close the underlying io.Reader. +// In order for the GZIP checksum to be verified, the reader must be +// fully consumed until the io.EOF. func (z *Reader) Close() error { return z.decompressor.Close() } diff --git a/src/compress/zlib/reader.go b/src/compress/zlib/reader.go index 30535fd980e55b..2efa1930354585 100644 --- a/src/compress/zlib/reader.go +++ b/src/compress/zlib/reader.go @@ -62,7 +62,8 @@ type Resetter interface { // NewReader creates a new ReadCloser. // Reads from the returned ReadCloser read and decompress data from r. -// The implementation buffers input and may read more data than necessary from r. +// If r does not implement io.ByteReader, the decompressor may read more +// data than necessary from r. // It is the caller's responsibility to call Close on the ReadCloser when done. // // The ReadCloser returned by NewReader also implements Resetter. @@ -115,6 +116,8 @@ func (z *reader) Read(p []byte) (int, error) { } // Calling Close does not close the wrapped io.Reader originally passed to NewReader. +// In order for the ZLIB checksum to be verified, the reader must be +// fully consumed until the io.EOF. func (z *reader) Close() error { if z.err != nil && z.err != io.EOF { return z.err From 256a9670cc9a0acd1fd70ad53ba7ab032d5b2933 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 9 May 2016 15:03:15 -0400 Subject: [PATCH 046/267] runtime: fix some out of date comments in bitmap code Change-Id: I4613aa6d62baba01686bbab10738a7de23daae30 Reviewed-on: https://go-review.googlesource.com/22971 Reviewed-by: Rick Hudson --- src/runtime/mbitmap.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index e01926e71a59a0..27f8e66d50ce1c 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -498,7 +498,6 @@ func (h heapBits) morePointers() bool { } // isPointer reports whether the heap bits describe a pointer word. -// h must describe the initial word of the object. // // nosplit because it is used during write barriers and must not be preempted. //go:nosplit @@ -507,8 +506,7 @@ func (h heapBits) isPointer() bool { } // hasPointers reports whether the given object has any pointers. -// It must be told how large the object at h is, so that it does not read too -// far into the bitmap. +// It must be told how large the object at h is for efficiency. // h must describe the initial word of the object. func (h heapBits) hasPointers(size uintptr) bool { if size == sys.PtrSize { // 1-word objects are always pointers From 561c94884477f568bdb68aacebfeb4d0411a874b Mon Sep 17 00:00:00 2001 From: Hana Kim Date: Mon, 9 May 2016 15:14:07 -0400 Subject: [PATCH 047/267] os: skip Lchown test on Android if symlink doesn't work After upgrading builder device (android/arm) to android 5.0.2, the test started failing. Running 'ln -s' from shell fails with permission error. Change-Id: I5b9e312806d58532b41ea3560ff079dabbc6424e Reviewed-on: https://go-review.googlesource.com/22962 Reviewed-by: Brad Fitzpatrick --- src/os/os_unix_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go index c47f5462ab56c8..5c10154760cbe7 100644 --- a/src/os/os_unix_test.go +++ b/src/os/os_unix_test.go @@ -145,6 +145,9 @@ func TestLchown(t *testing.T) { linkname := f.Name() + "2" if err := Symlink(f.Name(), linkname); err != nil { + if runtime.GOOS == "android" && IsPermission(err) { + t.Skip("skipping test on Android; permission error creating symlink") + } t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err) } defer Remove(linkname) From d88261fb6581106e4e7d8d6c63f0e33c2a24361e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 9 May 2016 17:21:11 +0000 Subject: [PATCH 048/267] time: don't depend on the io package The time package has never depended on the io package until a recent change during Go 1.7 to use the io.Seek* constants. The go/build dependency check didn't catch this because "time" was allowed to depend on meta package group "L0", which included "io". Adding the "io" package broke one of Dmitry's tools. The tool is fixable, but it's also not necessary for us to depend on "io" at all for some constants. Mirror the constants instead, and change deps_test.go to prevent an io dependency in the future. Change-Id: I74325228565279a74fa4a2f419643f5710e3e09f Reviewed-on: https://go-review.googlesource.com/22960 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/go/build/deps_test.go | 14 +++++++++++++- src/time/sys_plan9.go | 5 ++--- src/time/sys_unix.go | 5 ++--- src/time/sys_windows.go | 5 ++--- src/time/zoneinfo_read.go | 7 +++++++ 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 8a8c4be2174af0..d0d4fbba162967 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -136,7 +136,19 @@ var pkgDeps = map[string][]string{ "internal/syscall/unix": {"L0", "syscall"}, "internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"}, "internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"}, - "time": {"L0", "syscall", "internal/syscall/windows/registry"}, + "time": { + // "L0" without the "io" package: + "errors", + "runtime", + "runtime/internal/atomic", + "sync", + "sync/atomic", + "unsafe", + // Other time dependencies: + "internal/syscall/windows/registry", + "syscall", + }, + "os": {"L1", "os", "syscall", "time", "internal/syscall/windows"}, "path/filepath": {"L2", "os", "syscall"}, "io/ioutil": {"L2", "os", "path/filepath", "time"}, diff --git a/src/time/sys_plan9.go b/src/time/sys_plan9.go index 507d1159cfe9d5..11365a791f7dfc 100644 --- a/src/time/sys_plan9.go +++ b/src/time/sys_plan9.go @@ -8,7 +8,6 @@ package time import ( "errors" - "io" "syscall" ) @@ -56,9 +55,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := io.SeekStart + whence := seekStart if off < 0 { - whence = io.SeekEnd + whence = seekEnd } if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { return err diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go index dea03e06d51cf9..91d54c9ffd0a9e 100644 --- a/src/time/sys_unix.go +++ b/src/time/sys_unix.go @@ -8,7 +8,6 @@ package time import ( "errors" - "io" "syscall" ) @@ -56,9 +55,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := io.SeekStart + whence := seekStart if off < 0 { - whence = io.SeekEnd + whence = seekEnd } if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { return err diff --git a/src/time/sys_windows.go b/src/time/sys_windows.go index 4f41b1a7a3c64d..a4a068f78494c1 100644 --- a/src/time/sys_windows.go +++ b/src/time/sys_windows.go @@ -6,7 +6,6 @@ package time import ( "errors" - "io" "syscall" ) @@ -53,9 +52,9 @@ func closefd(fd uintptr) { } func preadn(fd uintptr, buf []byte, off int) error { - whence := io.SeekStart + whence := seekStart if off < 0 { - whence = io.SeekEnd + whence = seekEnd } if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil { return err diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index 66777f6d736151..19cd40d8477297 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -11,6 +11,13 @@ package time import "errors" +// Copies of io.Seek* constants to avoid importing "io": +const ( + seekStart = 0 + seekCurrent = 1 + seekEnd = 2 +) + // Simple I/O interface to binary blob of data. type data struct { p []byte From 9af83462c6f432b77a846a24b4d8efae9bdf0567 Mon Sep 17 00:00:00 2001 From: Tilman Dilo Date: Mon, 9 May 2016 23:37:07 +0200 Subject: [PATCH 049/267] crypto/cipher: execute AES-GCM decryption example The decryption example for AES-GCM was not executed, hiding the fact that the provided ciphertext could not be authenticated. This commit adds the required output comment, replaces the ciphertext with a working example, and removes an unnecessary string conversion along the way. Change-Id: Ie6729ca76cf4a56c48b33fb3b39872105faa604b Reviewed-on: https://go-review.googlesource.com/22953 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/crypto/cipher/example_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/crypto/cipher/example_test.go b/src/crypto/cipher/example_test.go index f6cc38650610ad..9abe782bca54ae 100644 --- a/src/crypto/cipher/example_test.go +++ b/src/crypto/cipher/example_test.go @@ -44,9 +44,9 @@ func ExampleNewGCMDecrypter() { // The key argument should be the AES key, either 16 or 32 bytes // to select AES-128 or AES-256. key := []byte("AES256Key-32Characters1234567890") - ciphertext, _ := hex.DecodeString("f90fbef747e7212ad7410d0eee2d965de7e890471695cddd2a5bc0ef5da1d04ad8147b62141ad6e4914aee8c512f64fba9037603d41de0d50b718bd665f019cdcd") + ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260") - nonce, _ := hex.DecodeString("bb8ef84243d2ee95a41c6c57") + nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d") block, err := aes.NewCipher(key) if err != nil { @@ -63,7 +63,8 @@ func ExampleNewGCMDecrypter() { panic(err.Error()) } - fmt.Printf("%s\n", string(plaintext)) + fmt.Printf("%s\n", plaintext) + // Output: exampleplaintext } func ExampleNewCBCDecrypter() { From f05c3aa24d815cd3869153750c9875e35fc48a6e Mon Sep 17 00:00:00 2001 From: Caleb Spare Date: Wed, 13 Apr 2016 16:51:25 -0700 Subject: [PATCH 050/267] encoding/json: support maps with integer keys This change makes encoding and decoding support integer types in map keys, converting to/from JSON string keys. JSON object keys are still sorted lexically, even though the keys may be integer strings. For backwards-compatibility, the existing Text(Un)Marshaler support for map keys (added in CL 20356) does not take precedence over the default encoding for string types. There is no such concern for integer types, so integer map key encoding is only used as a fallback if the map key type is not a Text(Un)Marshaler. Fixes #12529. Change-Id: I7e68c34f9cd19704b1d233a9862da15fabf0908a Reviewed-on: https://go-review.googlesource.com/22060 Reviewed-by: Brad Fitzpatrick --- src/encoding/json/decode.go | 52 +++++++++++++----- src/encoding/json/decode_test.go | 91 +++++++++++++++++++++++++++++++- src/encoding/json/encode.go | 37 ++++++++++--- 3 files changed, 158 insertions(+), 22 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 434edf8ea45096..2eda875bfdee8a 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -62,10 +62,10 @@ import ( // the additional Go array elements are set to zero values. // // To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal // reuses the existing map, keeping existing entries. Unmarshal then stores key- -// value pairs from the JSON object into the map. The map's key type must -// either be a string or implement encoding.TextUnmarshaler. +// value pairs from the JSON object into the map. The map's key type must +// either be a string, an integer, or implement encoding.TextUnmarshaler. // // If a JSON value is not appropriate for a given target type, // or if a JSON number overflows the target type, Unmarshal @@ -581,17 +581,24 @@ func (d *decodeState) object(v reflect.Value) { // Check type of target: // struct or - // map[string]T or map[encoding.TextUnmarshaler]T + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler switch v.Kind() { case reflect.Map: - // Map key must either have string kind or be an encoding.TextUnmarshaler. + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. t := v.Type() - if t.Key().Kind() != reflect.String && - !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } } if v.IsNil() { v.Set(reflect.MakeMap(t)) @@ -696,13 +703,32 @@ func (d *decodeState) object(v reflect.Value) { var kv reflect.Value switch { case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(v.Type().Key()) + kv = reflect.ValueOf(key).Convert(kt) case reflect.PtrTo(kt).Implements(textUnmarshalerType): kv = reflect.New(v.Type().Key()) d.literalStore(item, kv, true) kv = kv.Elem() default: - panic("json: Unexpected key type") // should never occur + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)}) + return + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)}) + return + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } } v.SetMapIndex(kv, subv) } diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 30e46ca44f07bd..7c388c0c272ff6 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -10,8 +10,10 @@ import ( "errors" "fmt" "image" + "math" "net" "reflect" + "strconv" "strings" "testing" "time" @@ -53,6 +55,8 @@ type tx struct { x int } +type u8 uint8 + // A type that can unmarshal itself. type unmarshaler struct { @@ -92,6 +96,29 @@ type ustructText struct { M unmarshalerText } +// u8marshal is an integer type that can marshal/unmarshal itself. +type u8marshal uint8 + +func (u8 u8marshal) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("u%d", u8)), nil +} + +var errMissingU8Prefix = errors.New("missing 'u' prefix") + +func (u8 *u8marshal) UnmarshalText(b []byte) error { + if !bytes.HasPrefix(b, []byte{'u'}) { + return errMissingU8Prefix + } + n, err := strconv.Atoi(string(b[1:])) + if err != nil { + return err + } + *u8 = u8marshal(n) + return nil +} + +var _ encoding.TextUnmarshaler = (*u8marshal)(nil) + var ( um0, um1 unmarshaler // target2 of unmarshaling ump = &um1 @@ -320,7 +347,69 @@ var unmarshalTests = []unmarshalTest{ {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, - // Map keys can be encoding.TextUnmarshalers + // integer-keyed map test + { + in: `{"-1":"a","0":"b","1":"c"}`, + ptr: new(map[int]string), + out: map[int]string{-1: "a", 0: "b", 1: "c"}, + }, + { + in: `{"0":"a","10":"c","9":"b"}`, + ptr: new(map[u8]string), + out: map[u8]string{0: "a", 9: "b", 10: "c"}, + }, + { + in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, + ptr: new(map[int64]string), + out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, + }, + { + in: `{"18446744073709551615":"max"}`, + ptr: new(map[uint64]string), + out: map[uint64]string{math.MaxUint64: "max"}, + }, + { + in: `{"0":false,"10":true}`, + ptr: new(map[uintptr]bool), + out: map[uintptr]bool{0: false, 10: true}, + }, + + // Check that MarshalText and UnmarshalText take precedence + // over default integer handling in map keys. + { + in: `{"u2":4}`, + ptr: new(map[u8marshal]int), + out: map[u8marshal]int{2: 4}, + }, + { + in: `{"2":4}`, + ptr: new(map[u8marshal]int), + err: errMissingU8Prefix, + }, + + // integer-keyed map errors + { + in: `{"abc":"abc"}`, + ptr: new(map[int]string), + err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2}, + }, + { + in: `{"256":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2}, + }, + { + in: `{"128":"abc"}`, + ptr: new(map[int8]string), + err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2}, + }, + { + in: `{"-1":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2}, + }, + + // Map keys can be encoding.TextUnmarshalers. {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, // If multiple values for the same key exists, only the most recent value is used. {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index d8c779869b33f8..8b967471ce70fc 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -117,9 +117,13 @@ import ( // an anonymous struct field in both current and earlier versions, give the field // a JSON tag of "-". // -// Map values encode as JSON objects. The map's key type must either be a string -// or implement encoding.TextMarshaler. The map keys are used as JSON object -// keys, subject to the UTF-8 coercion described for string values above. +// Map values encode as JSON objects. The map's key type must either be a +// string, an integer type, or implement encoding.TextMarshaler. The map keys +// are used as JSON object keys by applying the following rules, subject to the +// UTF-8 coercion described for string values above: +// - string keys are used directly +// - encoding.TextMarshalers are marshaled +// - integer keys are converted to strings // // Pointer values encode as the value pointed to. // A nil pointer encodes as the null JSON value. @@ -644,8 +648,14 @@ func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { } func newMapEncoder(t reflect.Type) encoderFunc { - if t.Key().Kind() != reflect.String && !t.Key().Implements(textMarshalerType) { - return unsupportedTypeEncoder + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !t.Key().Implements(textMarshalerType) { + return unsupportedTypeEncoder + } } me := &mapEncoder{typeEncoder(t.Elem())} return me.encode @@ -806,9 +816,20 @@ func (w *reflectWithString) resolve() error { w.s = w.v.String() return nil } - buf, err := w.v.Interface().(encoding.TextMarshaler).MarshalText() - w.s = string(buf) - return err + if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { + buf, err := tm.MarshalText() + w.s = string(buf) + return err + } + switch w.v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + w.s = strconv.FormatInt(w.v.Int(), 10) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + w.s = strconv.FormatUint(w.v.Uint(), 10) + return nil + } + panic("unexpected map key type") } // byString is a slice of reflectWithString where the reflect.Value is either From 3d82432288885696b01357e921ec00116291a790 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 19 Apr 2016 20:59:03 +0200 Subject: [PATCH 051/267] os: add TestReadAtOffset In the Plan 9 kernel, there used to be a bug in the implementation of the pread syscall, where the channel offset was erroneously updated after calling pread on a file. This test verifies that ReadAt is behaving as expected. Fixes #14534. Change-Id: Ifc9fd40a1f94879ee7eb09b2ffc369aa2bec2926 Reviewed-on: https://go-review.googlesource.com/22244 Run-TryBot: David du Colombier <0intro@gmail.com> Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/os/os_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/os/os_test.go b/src/os/os_test.go index de25f26614d452..baa2f07fd2b0f3 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1376,6 +1376,38 @@ func TestReadAt(t *testing.T) { } } +// Verify that ReadAt doesn't affect seek offset. +// In the Plan 9 kernel, there used to be a bug in the implementation of +// the pread syscall, where the channel offset was erroneously updated after +// calling pread on a file. +func TestReadAtOffset(t *testing.T) { + f := newFile("TestReadAtOffset", t) + defer Remove(f.Name()) + defer f.Close() + + const data = "hello, world\n" + io.WriteString(f, data) + + f.Seek(0, 0) + b := make([]byte, 5) + + n, err := f.ReadAt(b, 7) + if err != nil || n != len(b) { + t.Fatalf("ReadAt 7: %d, %v", n, err) + } + if string(b) != "world" { + t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") + } + + n, err = f.Read(b) + if err != nil || n != len(b) { + t.Fatalf("Read: %d, %v", n, err) + } + if string(b) != "hello" { + t.Fatalf("Read: have %q want %q", string(b), "hello") + } +} + func TestWriteAt(t *testing.T) { f := newFile("TestWriteAt", t) defer Remove(f.Name()) From a677724edfc465193d2f79ee48d2c06defbc916b Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 18 Apr 2016 03:18:13 +0200 Subject: [PATCH 052/267] os: enable TestGetppid on Plan 9 Fixes #8206. Change-Id: Iec1026ecc586495f5c9562cc84b3240c71d53da5 Reviewed-on: https://go-review.googlesource.com/22164 Run-TryBot: David du Colombier <0intro@gmail.com> TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/os/os_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/os/os_test.go b/src/os/os_test.go index baa2f07fd2b0f3..545bc1c8b0d25f 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1705,11 +1705,6 @@ func TestKillStartProcess(t *testing.T) { } func TestGetppid(t *testing.T) { - if runtime.GOOS == "plan9" { - // TODO: golang.org/issue/8206 - t.Skipf("skipping test on plan9; see issue 8206") - } - testenv.MustHaveExec(t) if Getenv("GO_WANT_HELPER_PROCESS") == "1" { From 42b647bde669ffa1d6f056eac20a683b9d02a786 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 10 May 2016 07:50:09 +0200 Subject: [PATCH 053/267] go/internal/gccgoimporter: remove workaround on Plan 9 We fixed the implementation of the pread syscall in the Plan 9 kernel, so calling pread doesn't update the channel offset when reading a file. Fixes #11194. Change-Id: Ie4019e445542a73479728af861a50bb54caea3f6 Reviewed-on: https://go-review.googlesource.com/22245 Reviewed-by: Minux Ma Run-TryBot: David du Colombier <0intro@gmail.com> TryBot-Result: Gobot Gobot --- src/go/internal/gccgoimporter/importer.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go index 65cc2df6860515..19b9c73568605f 100644 --- a/src/go/internal/gccgoimporter/importer.go +++ b/src/go/internal/gccgoimporter/importer.go @@ -88,12 +88,6 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e if err != nil { return } - // reset to offset 0 - needed on Plan 9 (see issue #11265) - // TODO: remove once issue #11265 has been resolved. - _, err = f.Seek(0, io.SeekStart) - if err != nil { - return - } var elfreader io.ReaderAt switch string(magic[:]) { From 9edb27e76f297c034e9383ad2d1bf48b23e1a25b Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 10 May 2016 07:06:47 -0700 Subject: [PATCH 054/267] reflect: make Field panic when out of bounds, as documented Fixes #15046. Change-Id: Iba7216297735be8e1ec550ce5336d17dcd3fd6b7 Reviewed-on: https://go-review.googlesource.com/22992 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/reflect/all_test.go | 35 +++++++++++++++++++++++++++++++++++ src/reflect/type.go | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index d4c3e4e588a89d..1a7952d7892d83 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -5221,6 +5221,41 @@ func TestLargeGCProg(t *testing.T) { fv.Call([]Value{ValueOf([256]*byte{})}) } +func fieldIndexRecover(t Type, i int) (recovered interface{}) { + defer func() { + recovered = recover() + }() + + t.Field(i) + return +} + +// Issue 15046. +func TestTypeFieldOutOfRangePanic(t *testing.T) { + typ := TypeOf(struct{ X int }{10}) + testIndices := [...]struct { + i int + mustPanic bool + }{ + 0: {-2, true}, + 1: {0, false}, + 2: {1, true}, + 3: {1 << 10, true}, + } + for i, tt := range testIndices { + recoveredErr := fieldIndexRecover(typ, tt.i) + if tt.mustPanic { + if recoveredErr == nil { + t.Errorf("#%d: fieldIndex %d expected to panic", i, tt.i) + } + } else { + if recoveredErr != nil { + t.Errorf("#%d: got err=%v, expected no panic", i, recoveredErr) + } + } + } +} + // Issue 9179. func TestCallGC(t *testing.T) { f := func(a, b, c, d, e string) { diff --git a/src/reflect/type.go b/src/reflect/type.go index 2ceb3d3f661726..b499d01a2c7346 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1178,7 +1178,7 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { // Field returns the i'th struct field. func (t *structType) Field(i int) (f StructField) { if i < 0 || i >= len(t.fields) { - return + panic("reflect: Field index out of bounds") } p := &t.fields[i] f.Type = toType(p.typ) From 636670b8db9b72c80ec89da0a666be0d686269fd Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Sun, 8 May 2016 18:17:59 -0700 Subject: [PATCH 055/267] net: use contexts for cgo-based DNS resolution Although calls to getaddrinfo can't be portably interrupted, we still benefit from more granular resource management by pushing the context downwards. Fixes #15321 Change-Id: I5506195fc6493080410e3d46aaa3fe02018a24fe Reviewed-on: https://go-review.googlesource.com/22961 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/cgo_stub.go | 12 ++-- src/net/cgo_unix.go | 136 +++++++++++++++++++++++++++++-------- src/net/cgo_unix_test.go | 61 ++++++++++++++++- src/net/lookup_unix.go | 12 ++-- src/net/netgo_unix_test.go | 5 +- 5 files changed, 180 insertions(+), 46 deletions(-) diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go index 52d1dfd3460e6c..51259722aec8e6 100644 --- a/src/net/cgo_stub.go +++ b/src/net/cgo_stub.go @@ -6,6 +6,8 @@ package net +import "context" + func init() { netGo = true } type addrinfoErrno int @@ -14,22 +16,22 @@ func (eai addrinfoErrno) Error() string { return "" } func (eai addrinfoErrno) Temporary() bool { return false } func (eai addrinfoErrno) Timeout() bool { return false } -func cgoLookupHost(name string) (addrs []string, err error, completed bool) { +func cgoLookupHost(ctx context.Context, name string) (addrs []string, err error, completed bool) { return nil, nil, false } -func cgoLookupPort(network, service string) (port int, err error, completed bool) { +func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) { return 0, nil, false } -func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { +func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) { return nil, nil, false } -func cgoLookupCNAME(name string) (cname string, err error, completed bool) { +func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) { return "", nil, false } -func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) { +func cgoLookupPTR(ctx context.Context, addr string) (ptrs []string, err error, completed bool) { return nil, nil, false } diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index 59c40c8d8a7f0c..5a1eed843751a4 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -19,6 +19,7 @@ package net import "C" import ( + "context" "syscall" "unsafe" ) @@ -32,18 +33,31 @@ func (eai addrinfoErrno) Error() string { return C.GoString(C.gai_strerror(C.i func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN } func (eai addrinfoErrno) Timeout() bool { return false } -func cgoLookupHost(name string) (hosts []string, err error, completed bool) { - addrs, err, completed := cgoLookupIP(name) +type portLookupResult struct { + port int + err error +} + +type ipLookupResult struct { + addrs []IPAddr + cname string + err error +} + +type reverseLookupResult struct { + names []string + err error +} + +func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) { + addrs, err, completed := cgoLookupIP(ctx, name) for _, addr := range addrs { hosts = append(hosts, addr.String()) } return } -func cgoLookupPort(network, service string) (port int, err error, completed bool) { - acquireThread() - defer releaseThread() - +func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) { var hints C.struct_addrinfo switch network { case "": // no hints @@ -64,11 +78,27 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool hints.ai_family = C.AF_INET6 } } + if ctx.Done() == nil { + port, err := cgoLookupServicePort(&hints, network, service) + return port, err, true + } + result := make(chan portLookupResult, 1) + go cgoPortLookup(result, &hints, network, service) + select { + case r := <-result: + return r.port, r.err, true + case <-ctx.Done(): + // Since there isn't a portable way to cancel the lookup, + // we just let it finish and write to the buffered channel. + return 0, mapErr(ctx.Err()), false + } +} +func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (port int, err error) { s := C.CString(service) var res *C.struct_addrinfo defer C.free(unsafe.Pointer(s)) - gerrno, err := C.getaddrinfo(nil, s, &hints, &res) + gerrno, err := C.getaddrinfo(nil, s, hints, &res) if gerrno != 0 { switch gerrno { case C.EAI_SYSTEM: @@ -78,7 +108,7 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool default: err = addrinfoErrno(gerrno) } - return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true + return 0, &DNSError{Err: err.Error(), Name: network + "/" + service} } defer C.freeaddrinfo(res) @@ -87,17 +117,22 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool case C.AF_INET: sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr)) p := (*[2]byte)(unsafe.Pointer(&sa.Port)) - return int(p[0])<<8 | int(p[1]), nil, true + return int(p[0])<<8 | int(p[1]), nil case C.AF_INET6: sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr)) p := (*[2]byte)(unsafe.Pointer(&sa.Port)) - return int(p[0])<<8 | int(p[1]), nil, true + return int(p[0])<<8 | int(p[1]), nil } } - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true + return 0, &DNSError{Err: "unknown port", Name: network + "/" + service} } -func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) { +func cgoPortLookup(result chan<- portLookupResult, hints *C.struct_addrinfo, network, service string) { + port, err := cgoLookupServicePort(hints, network, service) + result <- portLookupResult{port, err} +} + +func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) { acquireThread() defer releaseThread() @@ -127,7 +162,7 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com default: err = addrinfoErrno(gerrno) } - return nil, "", &DNSError{Err: err.Error(), Name: name}, true + return nil, "", &DNSError{Err: err.Error(), Name: name} } defer C.freeaddrinfo(res) @@ -156,17 +191,42 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com addrs = append(addrs, addr) } } - return addrs, cname, nil, true + return addrs, cname, nil } -func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { - addrs, _, err, completed = cgoLookupIPCNAME(name) - return +func cgoIPLookup(result chan<- ipLookupResult, name string) { + addrs, cname, err := cgoLookupIPCNAME(name) + result <- ipLookupResult{addrs, cname, err} } -func cgoLookupCNAME(name string) (cname string, err error, completed bool) { - _, cname, err, completed = cgoLookupIPCNAME(name) - return +func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) { + if ctx.Done() == nil { + addrs, _, err = cgoLookupIPCNAME(name) + return addrs, err, true + } + result := make(chan ipLookupResult, 1) + go cgoIPLookup(result, name) + select { + case r := <-result: + return r.addrs, r.err, true + case <-ctx.Done(): + return nil, mapErr(ctx.Err()), false + } +} + +func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) { + if ctx.Done() == nil { + _, cname, err = cgoLookupIPCNAME(name) + return cname, err, true + } + result := make(chan ipLookupResult, 1) + go cgoIPLookup(result, name) + select { + case r := <-result: + return r.cname, r.err, true + case <-ctx.Done(): + return "", mapErr(ctx.Err()), false + } } // These are roughly enough for the following: @@ -182,10 +242,7 @@ const ( maxNameinfoLen = 4096 ) -func cgoLookupPTR(addr string) ([]string, error, bool) { - acquireThread() - defer releaseThread() - +func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error, completed bool) { var zone string ip := parseIPv4(addr) if ip == nil { @@ -198,9 +255,26 @@ func cgoLookupPTR(addr string) ([]string, error, bool) { if sa == nil { return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true } - var err error - var b []byte + if ctx.Done() == nil { + names, err := cgoLookupAddrPTR(addr, sa, salen) + return names, err, true + } + result := make(chan reverseLookupResult, 1) + go cgoReverseLookup(result, addr, sa, salen) + select { + case r := <-result: + return r.names, r.err, true + case <-ctx.Done(): + return nil, mapErr(ctx.Err()), false + } +} + +func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (names []string, err error) { + acquireThread() + defer releaseThread() + var gerrno int + var b []byte for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { b = make([]byte, l) gerrno, err = cgoNameinfoPTR(b, sa, salen) @@ -217,16 +291,20 @@ func cgoLookupPTR(addr string) ([]string, error, bool) { default: err = addrinfoErrno(gerrno) } - return nil, &DNSError{Err: err.Error(), Name: addr}, true + return nil, &DNSError{Err: err.Error(), Name: addr} } - for i := 0; i < len(b); i++ { if b[i] == 0 { b = b[:i] break } } - return []string{absDomainName(b)}, nil, true + return []string{absDomainName(b)}, nil +} + +func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *C.struct_sockaddr, salen C.socklen_t) { + names, err := cgoLookupAddrPTR(addr, sa, salen) + result <- reverseLookupResult{names, err} } func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) { diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go index 5dc7b1a62d4663..e861c7aa1f90d8 100644 --- a/src/net/cgo_unix_test.go +++ b/src/net/cgo_unix_test.go @@ -13,15 +13,70 @@ import ( ) func TestCgoLookupIP(t *testing.T) { - host := "localhost" - _, err, ok := cgoLookupIP(host) + ctx := context.Background() + _, err, ok := cgoLookupIP(ctx, "localhost") if !ok { t.Errorf("cgoLookupIP must not be a placeholder") } if err != nil { t.Error(err) } - if _, err := goLookupIP(context.Background(), host); err != nil { +} + +func TestCgoLookupIPWithCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err, ok := cgoLookupIP(ctx, "localhost") + if !ok { + t.Errorf("cgoLookupIP must not be a placeholder") + } + if err != nil { + t.Error(err) + } +} + +func TestCgoLookupPort(t *testing.T) { + ctx := context.Background() + _, err, ok := cgoLookupPort(ctx, "tcp", "smtp") + if !ok { + t.Errorf("cgoLookupPort must not be a placeholder") + } + if err != nil { + t.Error(err) + } +} + +func TestCgoLookupPortWithCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err, ok := cgoLookupPort(ctx, "tcp", "smtp") + if !ok { + t.Errorf("cgoLookupPort must not be a placeholder") + } + if err != nil { + t.Error(err) + } +} + +func TestCgoLookupPTR(t *testing.T) { + ctx := context.Background() + _, err, ok := cgoLookupPTR(ctx, "127.0.0.1") + if !ok { + t.Errorf("cgoLookupPTR must not be a placeholder") + } + if err != nil { + t.Error(err) + } +} + +func TestCgoLookupPTRWithCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err, ok := cgoLookupPTR(ctx, "127.0.0.1") + if !ok { + t.Errorf("cgoLookupPTR must not be a placeholder") + } + if err != nil { t.Error(err) } } diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index 5461fe8a411e8d..15397e8105a92e 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -55,7 +55,7 @@ func lookupProtocol(_ context.Context, name string) (int, error) { func lookupHost(ctx context.Context, host string) (addrs []string, err error) { order := systemConf().hostLookupOrder(host) if order == hostLookupCgo { - if addrs, err, ok := cgoLookupHost(host); ok { + if addrs, err, ok := cgoLookupHost(ctx, host); ok { return addrs, err } // cgo not available (or netgo); fall back to Go's DNS resolver @@ -67,8 +67,7 @@ func lookupHost(ctx context.Context, host string) (addrs []string, err error) { func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) { order := systemConf().hostLookupOrder(host) if order == hostLookupCgo { - // TODO(bradfitz): push down ctx, or at least its deadline to start - if addrs, err, ok := cgoLookupIP(host); ok { + if addrs, err, ok := cgoLookupIP(ctx, host); ok { return addrs, err } // cgo not available (or netgo); fall back to Go's DNS resolver @@ -84,7 +83,7 @@ func lookupPort(ctx context.Context, network, service string) (int, error) { // files might be on a remote filesystem, though. This should // probably race goroutines if ctx != context.Background(). if systemConf().canUseCgo() { - if port, err, ok := cgoLookupPort(network, service); ok { + if port, err, ok := cgoLookupPort(ctx, network, service); ok { return port, err } } @@ -93,8 +92,7 @@ func lookupPort(ctx context.Context, network, service string) (int, error) { func lookupCNAME(ctx context.Context, name string) (string, error) { if systemConf().canUseCgo() { - // TODO: use ctx. issue 15321. Or race goroutines. - if cname, err, ok := cgoLookupCNAME(name); ok { + if cname, err, ok := cgoLookupCNAME(ctx, name); ok { return cname, err } } @@ -161,7 +159,7 @@ func lookupTXT(ctx context.Context, name string) ([]string, error) { func lookupAddr(ctx context.Context, addr string) ([]string, error) { if systemConf().canUseCgo() { - if ptrs, err, ok := cgoLookupPTR(addr); ok { + if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok { return ptrs, err } } diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go index 0a118874c25aef..5f1eb19e1240bd 100644 --- a/src/net/netgo_unix_test.go +++ b/src/net/netgo_unix_test.go @@ -14,14 +14,15 @@ import ( func TestGoLookupIP(t *testing.T) { host := "localhost" - _, err, ok := cgoLookupIP(host) + ctx := context.Background() + _, err, ok := cgoLookupIP(ctx, host) if ok { t.Errorf("cgoLookupIP must be a placeholder") } if err != nil { t.Error(err) } - if _, err := goLookupIP(context.Background(), host); err != nil { + if _, err := goLookupIP(ctx, host); err != nil { t.Error(err) } } From 9e96ad851d9fb3feb7ee3f7b72213c5b7a9977aa Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 10 May 2016 09:10:43 -0700 Subject: [PATCH 056/267] test: add test for unlowered ITab See #15604. This was a bug in a CL that has since been rolled back. Adding a test to challenge the next attempter. Change-Id: Ic43be254ea6eaab0071018cdc61d9b1c21f19cbf Reviewed-on: https://go-review.googlesource.com/23000 Reviewed-by: Brad Fitzpatrick Reviewed-by: Matthew Dempsky --- test/fixedbugs/issue15604.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/fixedbugs/issue15604.go diff --git a/test/fixedbugs/issue15604.go b/test/fixedbugs/issue15604.go new file mode 100644 index 00000000000000..4dc0b0b0541308 --- /dev/null +++ b/test/fixedbugs/issue15604.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bug + +import "os" + +func f(err error) { + var ok bool + if err, ok = err.(*os.PathError); ok { + if err == os.ErrNotExist { + } + } +} From 78ff74375930d5ae391beae562c91da40e5d92a4 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 10 May 2016 09:24:57 -0700 Subject: [PATCH 057/267] crypto/sha1: disable crashing AVX2 optimizations for now Updates #15617 Change-Id: I2104776f8e789d987b4f2f7f08f2ebe979b747a1 Reviewed-on: https://go-review.googlesource.com/23001 Run-TryBot: Brad Fitzpatrick Reviewed-by: Dmitry Vyukov Reviewed-by: Minux Ma --- src/crypto/sha1/sha1block_amd64.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go index 84f8a520197db2..a36f334b115d5b 100644 --- a/src/crypto/sha1/sha1block_amd64.go +++ b/src/crypto/sha1/sha1block_amd64.go @@ -12,7 +12,9 @@ func blockAVX2(dig *digest, p []byte) func blockAMD64(dig *digest, p []byte) func checkAVX2() bool -var hasAVX2 = checkAVX2() +// TODO(TocarIP): fix AVX2 crash (golang.org/issue/15617) and +// then re-enable this: +var hasAVX2 = false // checkAVX2() func block(dig *digest, p []byte) { if hasAVX2 && len(p) >= 256 { From f77f22b2bf43f565ac0933c8e1068c387e4007c3 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 10 May 2016 09:46:39 -0700 Subject: [PATCH 058/267] net/http: update bundled x/net/http2 Updates x/net/http2 to git rev 96dbb961 for golang.org/cl/23002 Fixes #15366 Updates #15134 (server part remains) Change-Id: I29336e624706f906b754da66381a620ae3293c6c Reviewed-on: https://go-review.googlesource.com/23003 Reviewed-by: Andrew Gerrand Run-TryBot: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/net/http/clientserver_test.go | 11 ---- src/net/http/h2_bundle.go | 91 +++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index 9c3949fc3970f8..39c1eaa04afadb 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -229,11 +229,6 @@ func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string) } slurp, err := ioutil.ReadAll(res.Body) - // TODO(bradfitz): short-term hack. Fix the - // http2 side of golang.org/issue/15366 once - // the http1 part is submitted. - res.Uncompressed = false - res.Body.Close() res.Body = slurpResult{ ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)), @@ -1176,12 +1171,6 @@ func TestH12_AutoGzipWithDumpResponse(t *testing.T) { io.WriteString(w, "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00") }, EarlyCheckResponse: func(proto string, res *Response) { - if proto == "HTTP/2.0" { - // TODO(bradfitz): Fix the http2 side - // of golang.org/issue/15366 once the - // http1 part is submitted. - return - } if !res.Uncompressed { t.Errorf("%s: expected Uncompressed to be set", proto) } diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 7cfe72a5dc8475..c2a2d37f6dfaa8 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "compress/gzip" + "context" "crypto/tls" "encoding/binary" "errors" @@ -1086,7 +1087,14 @@ func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error return f, nil } -var http2errStreamID = errors.New("invalid streamid") +var ( + http2errStreamID = errors.New("invalid stream ID") + http2errDepStreamID = errors.New("invalid dependent stream ID") +) + +func http2validStreamIDOrZero(streamID uint32) bool { + return streamID&(1<<31) == 0 +} func http2validStreamID(streamID uint32) bool { return streamID != 0 && streamID&(1<<31) == 0 @@ -1452,8 +1460,8 @@ func (f *http2Framer) WriteHeaders(p http2HeadersFrameParam) error { } if !p.Priority.IsZero() { v := p.Priority.StreamDep - if !http2validStreamID(v) && !f.AllowIllegalWrites { - return errors.New("invalid dependent stream id") + if !http2validStreamIDOrZero(v) && !f.AllowIllegalWrites { + return http2errDepStreamID } if p.Priority.Exclusive { v |= 1 << 31 @@ -1521,6 +1529,9 @@ func (f *http2Framer) WritePriority(streamID uint32, p http2PriorityParam) error if !http2validStreamID(streamID) && !f.AllowIllegalWrites { return http2errStreamID } + if !http2validStreamIDOrZero(p.StreamDep) { + return http2errDepStreamID + } f.startWrite(http2FramePriority, 0, streamID) v := p.StreamDep if p.Exclusive { @@ -1962,7 +1973,9 @@ func http2summarizeFrame(f http2Frame) string { return buf.String() } -func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel } +func http2reqContext(r *Request) context.Context { return r.Context() } + +func http2setResponseUncompressed(res *Response) { res.Uncompressed = true } var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1" @@ -2476,7 +2489,7 @@ func http2mustUint31(v int32) uint32 { } // bodyAllowedForStatus reports whether a given response status code -// permits a body. See RFC2616, section 4.4. +// permits a body. See RFC 2616, section 4.4. func http2bodyAllowedForStatus(status int) bool { switch { case status >= 100 && status <= 199: @@ -3989,6 +4002,8 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { if f.Truncated { handler = http2handleHeaderListTooLong + } else if err := http2checkValidHTTP2Request(req); err != nil { + handler = http2new400Handler(err) } go sc.runHandler(rw, req, handler) @@ -4707,6 +4722,37 @@ func http2foreachHeaderElement(v string, fn func(string)) { } } +// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2 +var http2connHeaders = []string{ + "Connection", + "Keep-Alive", + "Proxy-Connection", + "Transfer-Encoding", + "Upgrade", +} + +// checkValidHTTP2Request checks whether req is a valid HTTP/2 request, +// per RFC 7540 Section 8.1.2.2. +// The returned error is reported to users. +func http2checkValidHTTP2Request(req *Request) error { + for _, h := range http2connHeaders { + if _, ok := req.Header[h]; ok { + return fmt.Errorf("request header %q is not valid in HTTP/2", h) + } + } + te := req.Header["Te"] + if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) { + return errors.New(`request header "TE" may only be "trailers" in HTTP/2`) + } + return nil +} + +func http2new400Handler(err error) HandlerFunc { + return func(w ResponseWriter, r *Request) { + Error(w, err.Error(), StatusBadRequest) + } +} + const ( // transportDefaultConnFlow is how many connection-level flow control // tokens we give the server at start-up, past the default 64k. @@ -4875,18 +4921,22 @@ type http2clientStream struct { } // awaitRequestCancel runs in its own goroutine and waits for the user -// to either cancel a RoundTrip request (using the provided -// Request.Cancel channel), or for the request to be done (any way it -// might be removed from the cc.streams map: peer reset, successful -// completion, TCP connection breakage, etc) -func (cs *http2clientStream) awaitRequestCancel(cancel <-chan struct{}) { - if cancel == nil { +// to cancel a RoundTrip request, its context to expire, or for the +// request to be done (any way it might be removed from the cc.streams +// map: peer reset, successful completion, TCP connection breakage, +// etc) +func (cs *http2clientStream) awaitRequestCancel(req *Request) { + ctx := http2reqContext(req) + if req.Cancel == nil && ctx.Done() == nil { return } select { - case <-cancel: + case <-req.Cancel: cs.bufPipe.CloseWithError(http2errRequestCanceled) cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) + case <-ctx.Done(): + cs.bufPipe.CloseWithError(ctx.Err()) + cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) case <-cs.done: } } @@ -5334,8 +5384,8 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } readLoopResCh := cs.resc - requestCanceledCh := http2requestCancel(req) bodyWritten := false + ctx := http2reqContext(req) for { select { @@ -5360,7 +5410,15 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } return nil, http2errTimeout - case <-requestCanceledCh: + case <-ctx.Done(): + cc.forgetStreamID(cs.ID) + if !hasBody || bodyWritten { + cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) + } else { + cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) + } + return nil, ctx.Err() + case <-req.Cancel: cc.forgetStreamID(cs.ID) if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) @@ -5568,7 +5626,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail case "host", "content-length": continue - case "connection", "proxy-connection", "transfer-encoding", "upgrade": + case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive": continue case "user-agent": @@ -5892,13 +5950,14 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http cs.bufPipe = http2pipe{b: buf} cs.bytesRemain = res.ContentLength res.Body = http2transportResponseBody{cs} - go cs.awaitRequestCancel(http2requestCancel(cs.req)) + go cs.awaitRequestCancel(cs.req) if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { res.Header.Del("Content-Encoding") res.Header.Del("Content-Length") res.ContentLength = -1 res.Body = &http2gzipReader{body: res.Body} + http2setResponseUncompressed(res) } return res, nil } From 81a89606ef7e1334a0a23dab2eaa295b381caebc Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 10 May 2016 11:48:48 -0700 Subject: [PATCH 059/267] doc: remove mention of %HOME% from installation instructions Fixes #15598 Change-Id: I4cfb8799dab0e9e34cae2e61839911fd65e4cfa3 Reviewed-on: https://go-review.googlesource.com/23004 Reviewed-by: Brad Fitzpatrick --- doc/install.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install.html b/doc/install.html index 96a7672778bb69..0e6b86fdaf5d15 100644 --- a/doc/install.html +++ b/doc/install.html @@ -221,7 +221,7 @@

Test your installation

Create a directory to contain your workspace, $HOME/work - + for example, and set the GOPATH environment variable to point to that location.

@@ -231,7 +231,7 @@

Test your installation

From 9780bf2a9587b6aa0c92526cc1d6d6d1ed4c7210 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 10 May 2016 14:27:32 -0700 Subject: [PATCH 060/267] os/user: don't create C function mygetgrouplist Instead of exporting the C function mygetgrouplist as a global symbol to conflict with other symbols of the same name, use trivial Go code and a static C function. Change-Id: I98dd667814d0a0ed8f7b1d4cfc6483d5a6965b26 Reviewed-on: https://go-review.googlesource.com/23008 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- ...{getgrouplist_darwin.c => getgrouplist_darwin.go} | 11 +++++++++-- .../{getgrouplist_unix.c => getgrouplist_unix.go} | 12 ++++++++++-- src/os/user/listgroups_unix.go | 6 ++---- 3 files changed, 21 insertions(+), 8 deletions(-) rename src/os/user/{getgrouplist_darwin.c => getgrouplist_darwin.go} (64%) rename src/os/user/{getgrouplist_unix.c => getgrouplist_unix.go} (56%) diff --git a/src/os/user/getgrouplist_darwin.c b/src/os/user/getgrouplist_darwin.go similarity index 64% rename from src/os/user/getgrouplist_darwin.c rename to src/os/user/getgrouplist_darwin.go index 6ad561489829ea..54a2da3610434c 100644 --- a/src/os/user/getgrouplist_darwin.c +++ b/src/os/user/getgrouplist_darwin.go @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo +package user +/* #include #include #include -int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) { +static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) { int* buf = malloc(*ngroups * sizeof(int)); int rv = getgrouplist(user, (int) group, buf, ngroups); int i; @@ -20,3 +21,9 @@ int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) { free(buf); return rv; } +*/ +import "C" + +func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int { + return C.mygetgrouplist(name, userGID, gids, n) +} diff --git a/src/os/user/getgrouplist_unix.c b/src/os/user/getgrouplist_unix.go similarity index 56% rename from src/os/user/getgrouplist_unix.c rename to src/os/user/getgrouplist_unix.go index eb14f9ab8a0ac1..14da7c00a2b55d 100644 --- a/src/os/user/getgrouplist_unix.c +++ b/src/os/user/getgrouplist_unix.go @@ -2,13 +2,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo // +build dragonfly freebsd !android,linux netbsd openbsd +package user + +/* #include #include #include -int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) { +static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) { return getgrouplist(user, group, groups, ngroups); } +*/ +import "C" + +func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int { + return C.mygetgrouplist(name, userGID, gids, n) +} diff --git a/src/os/user/listgroups_unix.go b/src/os/user/listgroups_unix.go index f78baaac1e27f7..db952c64bffdb3 100644 --- a/src/os/user/listgroups_unix.go +++ b/src/os/user/listgroups_unix.go @@ -16,8 +16,6 @@ import ( #include #include #include - -extern int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups); */ import "C" @@ -32,7 +30,7 @@ func listGroups(u *User) ([]string, error) { n := C.int(256) gidsC := make([]C.gid_t, n) - rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n) + rv := getGroupList(nameC, userGID, &gidsC[0], &n) if rv == -1 { // More than initial buffer, but now n contains the correct size. const maxGroups = 2048 @@ -40,7 +38,7 @@ func listGroups(u *User) ([]string, error) { return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups) } gidsC = make([]C.gid_t, n) - rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n) + rv := getGroupList(nameC, userGID, &gidsC[0], &n) if rv == -1 { return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username) } From 9628e6fd1d1afeedce7c4b45454e0bc5cbd0d5ff Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 10 May 2016 15:32:00 -0700 Subject: [PATCH 061/267] runtime/testdata/testprogcgo: fix Windows C compiler warning Noticed and fix by Alex Brainman. Tested in https://golang.org/cl/23005 (which makes all compiler warnings fatal during development) Fixes #15623 Change-Id: Ic19999fce8bb8640d963965cc328574efadd7855 Reviewed-on: https://go-review.googlesource.com/23010 Reviewed-by: Alex Brainman --- src/runtime/testdata/testprogcgo/threadpanic_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/testdata/testprogcgo/threadpanic_windows.c b/src/runtime/testdata/testprogcgo/threadpanic_windows.c index 6f896634a6d946..ba66d0f5c9564f 100644 --- a/src/runtime/testdata/testprogcgo/threadpanic_windows.c +++ b/src/runtime/testdata/testprogcgo/threadpanic_windows.c @@ -8,7 +8,7 @@ void gopanic(void); -static unsigned int +static unsigned int __attribute__((__stdcall__)) die(void* x) { gopanic(); From b6712946c1b46eb629fb010e65e5b3735f94d171 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 7 Apr 2016 15:12:32 +1000 Subject: [PATCH 062/267] runtime: make mksyscall_windows.go flags do what they say they do The -systemdll and -xsys flags generate broken code in some situations (see issue for details). Fix all that. This CL only fixes bugs in existing code, but I have more changes comming: golang.org/x/sys/windows is not the only package that uses mksyscall_windows.go. golang.org/x/exp/shiny and github.com/derekparker/delve do too. I also have few personal packages that use mksyscall_windows.go. None of those packages are aware of new -xsys flag. I would like to change mksyscall_windows.go, so external packages do not need to use -xsys flag. I would love to get rid of -xsys flag altogether, but I don't see how it is possible. So I will, probably, replace -xsys with a flag that means opposite to -xsys, and use new flag everywhere in standard libraries. Flag name suggestions are welcome. -systemdll flag makes users code more "secure". I would like to make -systemdll behaviour a default for all mksyscall_windows.go users. We use that already in standard library. If we think "secure" is important, we should encourage it in all users code. If mksyscall_windows.go user insist on using old code, provide -use_old_loaddll (need good name here) flag for that. So -systemdll flag will be replaced with -use_old_loaddll. Fixes #15167 Change-Id: I516369507867358ba1b66aabe00a17a7b477016e Reviewed-on: https://go-review.googlesource.com/21645 Reviewed-by: Brad Fitzpatrick --- src/syscall/mksyscall_windows.go | 47 ++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index a6cef6fca79e93..a0663073090faf 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -617,9 +617,6 @@ func ParseFiles(fs []string) (*Source, error) { "unsafe", }, } - if *systemDLL { - src.Import("internal/syscall/windows/sysdll") - } for _, file := range fs { if err := src.ParseFile(file); err != nil { return nil, err @@ -691,8 +688,29 @@ func (src *Source) ParseFile(path string) error { // Generate output source file from a source set src. func (src *Source) Generate(w io.Writer) error { - if *sysRepo && packageName != "windows" { - src.Import("golang.org/x/sys/windows") + const ( + pkgStd = iota // any package in std library + pkgXSysWindows // x/sys/windows package + pkgOther + ) + var pkgtype int + switch { + case !*sysRepo: + pkgtype = pkgStd + case packageName == "windows": + // TODO: this needs better logic than just using package name + pkgtype = pkgXSysWindows + default: + pkgtype = pkgOther + } + if *systemDLL { + switch pkgtype { + case pkgStd: + src.Import("internal/syscall/windows/sysdll") + case pkgXSysWindows: + default: + src.Import("golang.org/x/sys/windows") + } } if packageName != "syscall" { src.Import("syscall") @@ -702,18 +720,17 @@ func (src *Source) Generate(w io.Writer) error { "syscalldot": syscalldot, "newlazydll": func(dll string) string { arg := "\"" + dll + ".dll\"" - if *systemDLL { - arg = "sysdll.Add(" + arg + ")" - } - if *sysRepo { - if packageName == "windows" { - return "NewLazySystemDLL(" + arg + ")" - } else { - return "windows.NewLazySystemDLL(" + arg + ")" - } - } else { + if !*systemDLL { return syscalldot() + "NewLazyDLL(" + arg + ")" } + switch pkgtype { + case pkgStd: + return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))" + case pkgXSysWindows: + return "NewLazySystemDLL(" + arg + ")" + default: + return "windows.NewLazySystemDLL(" + arg + ")" + } }, } t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate)) From d958dab095febfe542c6209b023d15f1d0de7128 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 10 May 2016 17:06:19 -0700 Subject: [PATCH 063/267] go/importer: use correct path when checking if package was already imported The importer uses a global (shared) package map across multiple imports to determine if a package was imported before. That package map is usually indexed by package (import) path ('id' in this code). However, the binary importer was using the incoming (possibly unclean) path. Fixes #15517. Change-Id: I0c32a708dfccf345e0353fbda20ad882121e437c Reviewed-on: https://go-review.googlesource.com/23012 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/go/internal/gcimporter/bimport.go | 2 +- src/go/internal/gcimporter/gcimporter.go | 2 +- src/go/internal/gcimporter/gcimporter_test.go | 39 +++++++++++++++++++ src/go/internal/gcimporter/testdata/p.go | 13 +++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/go/internal/gcimporter/testdata/p.go diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index 964bf5512e080c..341358287a1ffd 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -170,7 +170,7 @@ func (p *importer) declare(obj types.Object) { // imported. // (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj, // switch case importing functions). - panic(fmt.Sprintf("%s already declared", alt.Name())) + panic(fmt.Sprintf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)) } } diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index b2848c3023696a..2c6e676225fb14 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -163,7 +163,7 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types var data []byte data, err = ioutil.ReadAll(buf) if err == nil { - _, pkg, err = BImportData(packages, data, path) + _, pkg, err = BImportData(packages, data, id) return } default: diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index 8b94f9a105a6c1..8de36c713c1453 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -361,3 +361,42 @@ func TestIssue13898(t *testing.T) { t.Fatalf("found %v; want go/types", m.Pkg()) } } + +func TestIssue15517(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + // On windows, we have to set the -D option for the compiler to avoid having a drive + // letter and an illegal ':' in the import path - just skip it (see also issue #3483). + if runtime.GOOS == "windows" { + t.Skip("avoid dealing with relative paths/drive letters on windows") + } + + if f := compile(t, "testdata", "p.go"); f != "" { + defer os.Remove(f) + } + + // Multiple imports of p must succeed without redeclaration errors. + // We use an import path that's not cleaned up so that the eventual + // file path for the package is different from the package path; this + // will expose the error if it is present. + // + // (Issue: Both the textual and the binary importer used the file path + // of the package to be imported as key into the shared packages map. + // However, the binary importer then used the package path to identify + // the imported package to mark it as complete; effectively marking the + // wrong package as complete. By using an "unclean" package path, the + // file and package path are different, exposing the problem if present. + // The same issue occurs with vendoring.) + imports := make(map[string]*types.Package) + for i := 0; i < 3; i++ { + if _, err := Import(imports, "./././testdata/p", "."); err != nil { + t.Fatal(err) + } + } +} diff --git a/src/go/internal/gcimporter/testdata/p.go b/src/go/internal/gcimporter/testdata/p.go new file mode 100644 index 00000000000000..9e2e7057653725 --- /dev/null +++ b/src/go/internal/gcimporter/testdata/p.go @@ -0,0 +1,13 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Input for TestIssue15517 + +package p + +const C = 0 + +var V int + +func F() {} From 0efc16284bc4fd5b8b31d3f6b6763f98700c5664 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 11 May 2016 15:19:32 +1000 Subject: [PATCH 064/267] syscall: remove mksyscall_windows.go -xsys flag Also run "go generate" in internal/syscall/windows and internal/syscall/windows/registry Updates #15167 Change-Id: I0109226962f81857fe11d308b869d561ea8ed9f9 Reviewed-on: https://go-review.googlesource.com/23021 Reviewed-by: Brad Fitzpatrick Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot --- .../windows/registry/zsyscall_windows.go | 8 ++++-- .../syscall/windows/zsyscall_windows.go | 8 ++++-- src/syscall/mksyscall_windows.go | 28 +++++++++++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go index 7e473d4e1de7b2..62affc0b50baf4 100644 --- a/src/internal/syscall/windows/registry/zsyscall_windows.go +++ b/src/internal/syscall/windows/registry/zsyscall_windows.go @@ -2,9 +2,11 @@ package registry -import "unsafe" -import "syscall" -import "internal/syscall/windows/sysdll" +import ( + "internal/syscall/windows/sysdll" + "syscall" + "unsafe" +) var _ unsafe.Pointer diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go index d599258976b81d..6929acfa7283f5 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -2,9 +2,11 @@ package windows -import "unsafe" -import "syscall" -import "internal/syscall/windows/sysdll" +import ( + "internal/syscall/windows/sysdll" + "syscall" + "unsafe" +) var _ unsafe.Pointer diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index a0663073090faf..4ccbb04908c7a5 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -57,6 +57,8 @@ import ( "io/ioutil" "log" "os" + "path/filepath" + "runtime" "sort" "strconv" "strings" @@ -67,7 +69,6 @@ var ( filename = flag.String("output", "", "output file name (standard output if omitted)") printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall") systemDLL = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory") - sysRepo = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo") ) func trim(s string) string { @@ -686,6 +687,23 @@ func (src *Source) ParseFile(path string) error { return nil } +// IsStdRepo returns true if src is part of standard library. +func (src *Source) IsStdRepo() (bool, error) { + if len(src.Files) == 0 { + return false, errors.New("no input files provided") + } + abspath, err := filepath.Abs(src.Files[0]) + if err != nil { + return false, err + } + goroot := runtime.GOROOT() + if runtime.GOOS == "windows" { + abspath = strings.ToLower(abspath) + goroot = strings.ToLower(goroot) + } + return strings.HasPrefix(abspath, goroot), nil +} + // Generate output source file from a source set src. func (src *Source) Generate(w io.Writer) error { const ( @@ -693,9 +711,13 @@ func (src *Source) Generate(w io.Writer) error { pkgXSysWindows // x/sys/windows package pkgOther ) + isStdRepo, err := src.IsStdRepo() + if err != nil { + return err + } var pkgtype int switch { - case !*sysRepo: + case isStdRepo: pkgtype = pkgStd case packageName == "windows": // TODO: this needs better logic than just using package name @@ -734,7 +756,7 @@ func (src *Source) Generate(w io.Writer) error { }, } t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate)) - err := t.Execute(w, src) + err = t.Execute(w, src) if err != nil { return errors.New("Failed to execute template: " + err.Error()) } From b4538d7aaa1a600dc1d3724f9aecb5c8039e1324 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 10 May 2016 07:43:17 +0000 Subject: [PATCH 065/267] Revert "os: enable TestGetppid on Plan 9" This reverts commit a677724edfc465193d2f79ee48d2c06defbc916b. Change-Id: I6a54ac26a6deca5b2a39ec9f899469a88b543d3d Reviewed-on: https://go-review.googlesource.com/22980 Reviewed-by: Brad Fitzpatrick --- src/os/os_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/os/os_test.go b/src/os/os_test.go index 545bc1c8b0d25f..baa2f07fd2b0f3 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1705,6 +1705,11 @@ func TestKillStartProcess(t *testing.T) { } func TestGetppid(t *testing.T) { + if runtime.GOOS == "plan9" { + // TODO: golang.org/issue/8206 + t.Skipf("skipping test on plan9; see issue 8206") + } + testenv.MustHaveExec(t) if Getenv("GO_WANT_HELPER_PROCESS") == "1" { From d1981ac313f6858cf1ec163dac94ea0d6904a731 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 10 May 2016 04:29:32 +0900 Subject: [PATCH 066/267] net: reorganize interface tests to avoid vague flakiness This change reorganizes test cases for surveying network interfaces and address prefixes to make sure which part of the functionality is broken. Updates #7849. Change-Id: If6918075802eef69a7f1ee040010b3c46f4f4b97 Reviewed-on: https://go-review.googlesource.com/22990 Reviewed-by: Brad Fitzpatrick --- src/net/interface_test.go | 292 +++++++++++++++++++++----------------- 1 file changed, 165 insertions(+), 127 deletions(-) diff --git a/src/net/interface_test.go b/src/net/interface_test.go index e1580134937de0..2603311d24ba29 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -5,6 +5,7 @@ package net import ( + "fmt" "internal/testenv" "reflect" "runtime" @@ -48,24 +49,16 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string { return "" } -type routeStats struct { - loop int // # of active loopback interfaces - other int // # of active other interfaces - - uni4, uni6 int // # of active connected unicast, anycast routes - multi4, multi6 int // # of active connected multicast route clones -} - func TestInterfaces(t *testing.T) { if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { - // 100% flaky, actually, at least on some FreeBSD versions - testenv.SkipFlaky(t, 15262) + // 100% flaky on FreeBSD 11-CURRENT and above. + testenv.SkipFlaky(t, 7849) } + ift, err := Interfaces() if err != nil { t.Fatal(err) } - var stats routeStats for _, ifi := range ift { ifxi, err := InterfaceByIndex(ifi.Index) if err != nil { @@ -81,196 +74,241 @@ func TestInterfaces(t *testing.T) { if !reflect.DeepEqual(ifxn, &ifi) { t.Errorf("got %v; want %v", ifxn, ifi) } - t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU) - t.Logf("hardware address %q", ifi.HardwareAddr.String()) - if ifi.Flags&FlagUp != 0 { - if ifi.Flags&FlagLoopback != 0 { - stats.loop++ - } else { - stats.other++ - } - } - n4, n6 := testInterfaceAddrs(t, &ifi) - stats.uni4 += n4 - stats.uni6 += n6 - n4, n6 = testInterfaceMulticastAddrs(t, &ifi) - stats.multi4 += n4 - stats.multi6 += n6 - } - switch runtime.GOOS { - case "nacl", "plan9", "solaris": - default: - // Test the existence of connected unicast routes for - // IPv4. - if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { - t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) - } - // Test the existence of connected unicast routes for - // IPv6. We can assume the existence of ::1/128 when - // 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) - } - } - switch runtime.GOOS { - case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris": - default: - // Test the existence of connected multicast route - // clones for IPv4. Unlike IPv6, IPv4 multicast - // capability is not a mandatory feature, and so this - // test is disabled. - //if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 { - // t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats) - //} - // Test the existence of connected multicast route - // clones for IPv6. Some platform never uses loopback - // interface as the nexthop for multicast routing. - // We can assume the existence of connected multicast - // route clones when at least two connected unicast - // routes, ::1/128 and other, are installed. - if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 { - t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats) - } + t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr) } } func TestInterfaceAddrs(t *testing.T) { + if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { + // 100% flaky on FreeBSD 11-CURRENT and above. + testenv.SkipFlaky(t, 7849) + } + ift, err := Interfaces() if err != nil { t.Fatal(err) } - var stats routeStats - for _, ifi := range ift { - if ifi.Flags&FlagUp != 0 { - if ifi.Flags&FlagLoopback != 0 { - stats.loop++ - } else { - stats.other++ - } - } - } + ifStats := interfaceStats(ift) ifat, err := InterfaceAddrs() if err != nil { t.Fatal(err) } - stats.uni4, stats.uni6 = testAddrs(t, ifat) - // Test the existence of connected unicast routes for IPv4. - if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { - t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) + uniStats, err := validateInterfaceUnicastAddrs(ifat) + if err != nil { + t.Fatal(err) } - // Test the existence of connected unicast routes for IPv6. - // We can assume the existence of ::1/128 when 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) + if err := checkUnicastStats(ifStats, uniStats); err != nil { + t.Fatal(err) } } -func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) { - ifat, err := ifi.Addrs() +func TestInterfaceUnicastAddrs(t *testing.T) { + if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { + // 100% flaky on FreeBSD 11-CURRENT and above. + testenv.SkipFlaky(t, 7849) + } + + ift, err := Interfaces() + if err != nil { + t.Fatal(err) + } + ifStats := interfaceStats(ift) if err != nil { t.Fatal(err) } - return testAddrs(t, ifat) + var uniStats routeStats + for _, ifi := range ift { + ifat, err := ifi.Addrs() + if err != nil { + t.Fatal(ifi, err) + } + stats, err := validateInterfaceUnicastAddrs(ifat) + if err != nil { + t.Fatal(ifi, err) + } + uniStats.ipv4 += stats.ipv4 + uniStats.ipv6 += stats.ipv6 + } + if err := checkUnicastStats(ifStats, &uniStats); err != nil { + t.Fatal(err) + } } -func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) { - ifmat, err := ifi.MulticastAddrs() +func TestInterfaceMulticastAddrs(t *testing.T) { + if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { + // 100% flaky on FreeBSD 11-CURRENT and above. + testenv.SkipFlaky(t, 7849) + } + + ift, err := Interfaces() if err != nil { t.Fatal(err) } - return testMulticastAddrs(t, ifmat) + ifStats := interfaceStats(ift) + ifat, err := InterfaceAddrs() + if err != nil { + t.Fatal(err) + } + uniStats, err := validateInterfaceUnicastAddrs(ifat) + if err != nil { + t.Fatal(err) + } + var multiStats routeStats + for _, ifi := range ift { + ifmat, err := ifi.MulticastAddrs() + if err != nil { + t.Fatal(ifi, err) + } + stats, err := validateInterfaceMulticastAddrs(ifmat) + if err != nil { + t.Fatal(ifi, err) + } + multiStats.ipv4 += stats.ipv4 + multiStats.ipv6 += stats.ipv6 + } + if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil { + t.Fatal(err) + } +} + +type ifStats struct { + loop int // # of active loopback interfaces + other int // # of active other interfaces +} + +func interfaceStats(ift []Interface) *ifStats { + var stats ifStats + for _, ifi := range ift { + if ifi.Flags&FlagUp != 0 { + if ifi.Flags&FlagLoopback != 0 { + stats.loop++ + } else { + stats.other++ + } + } + } + return &stats } -func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) { +type routeStats struct { + ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes +} + +func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) { // Note: BSD variants allow assigning any IPv4/IPv6 address // prefix to IP interface. For example, // - 0.0.0.0/0 through 255.255.255.255/32 // - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 // In other words, there is no tightly-coupled combination of // interface address prefixes and connected routes. + stats := new(routeStats) for _, ifa := range ifat { switch ifa := ifa.(type) { case *IPNet: if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil { - t.Errorf("unexpected value: %#v", ifa) - continue + return nil, fmt.Errorf("unexpected value: %#v", ifa) } if len(ifa.IP) != IPv6len { - t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa) - continue + return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) } prefixLen, maxPrefixLen := ifa.Mask.Size() if ifa.IP.To4() != nil { if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len { - t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen) - continue + return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) } if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122 - t.Errorf("unexpected prefix length for IPv4 loopback: %d/%d", prefixLen, maxPrefixLen) - continue + return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) } - naf4++ + stats.ipv4++ } if ifa.IP.To16() != nil && ifa.IP.To4() == nil { if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len { - t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen) - continue + return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) } if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291 - t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen) - continue + return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) } - naf6++ + stats.ipv6++ } - t.Logf("interface address %q", ifa.String()) case *IPAddr: if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() { - t.Errorf("unexpected value: %#v", ifa) - continue + return nil, fmt.Errorf("unexpected value: %#v", ifa) } if len(ifa.IP) != IPv6len { - t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa) - continue + return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) } if ifa.IP.To4() != nil { - naf4++ + stats.ipv4++ } if ifa.IP.To16() != nil && ifa.IP.To4() == nil { - naf6++ + stats.ipv6++ } - t.Logf("interface address %s", ifa.String()) default: - t.Errorf("unexpected type: %T", ifa) + return nil, fmt.Errorf("unexpected type: %T", ifa) } } - return + return stats, nil } -func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) { - for _, ifma := range ifmat { - switch ifma := ifma.(type) { +func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) { + stats := new(routeStats) + for _, ifa := range ifat { + switch ifa := ifa.(type) { case *IPAddr: - if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() { - t.Errorf("unexpected value: %+v", ifma) - continue + if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() { + return nil, fmt.Errorf("unexpected value: %#v", ifa) } - if len(ifma.IP) != IPv6len { - t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifma) - continue + if len(ifa.IP) != IPv6len { + return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) } - if ifma.IP.To4() != nil { - nmaf4++ + if ifa.IP.To4() != nil { + stats.ipv4++ } - if ifma.IP.To16() != nil && ifma.IP.To4() == nil { - nmaf6++ + if ifa.IP.To16() != nil && ifa.IP.To4() == nil { + stats.ipv6++ } - t.Logf("joined group address %q", ifma.String()) default: - t.Errorf("unexpected type: %T", ifma) + return nil, fmt.Errorf("unexpected type: %T", ifa) } } - return + return stats, nil +} + +func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error { + // Test the existence of connected unicast routes for IPv4. + if supportsIPv4 && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 { + return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats) + } + // Test the existence of connected unicast routes for IPv6. + // We can assume the existence of ::1/128 when at least one + // loopback interface is installed. + if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 == 0 { + return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats) + } + return nil +} + +func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error { + switch runtime.GOOS { + case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris": + default: + // Test the existence of connected multicast route + // clones for IPv4. Unlike IPv6, IPv4 multicast + // capability is not a mandatory feature, and so IPv4 + // multicast validation is ignored and we only check + // IPv6 below. + // + // Test the existence of connected multicast route + // clones for IPv6. Some platform never uses loopback + // interface as the nexthop for multicast routing. + // We can assume the existence of connected multicast + // route clones when at least two connected unicast + // routes, ::1/128 and other, are installed. + if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 { + return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats) + } + } + return nil } func BenchmarkInterfaces(b *testing.B) { From c1e88920606e78b06e936c9c249bd55f06dd8c51 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 11 May 2016 13:04:22 +0900 Subject: [PATCH 067/267] net: fix nits found by vet Change-Id: I323231f31c4e1e7415661ebd943a90b2f1e9da1c Reviewed-on: https://go-review.googlesource.com/23020 Reviewed-by: Ian Lance Taylor --- src/net/dnsclient_unix_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index c1ef5a32d3dcd6..09bbd488660673 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -582,11 +582,11 @@ func TestIgnoreLameReferrals(t *testing.T) { } if got := len(addrs); got != 1 { - t.Fatal("got %d addresses, want 1", got) + t.Fatalf("got %d addresses, want 1", got) } if got, want := addrs[0].String(), "192.0.2.1"; got != want { - t.Fatal("got address %v, want %v", got, want) + t.Fatalf("got address %v, want %v", got, want) } } @@ -721,6 +721,6 @@ func TestIgnoreDNSForgeries(t *testing.T) { } if got := resp.answer[0].(*dnsRR_A).A; got != TestAddr { - t.Error("got address %v, want %v", got, TestAddr) + t.Errorf("got address %v, want %v", got, TestAddr) } } From 80423f1e64f1e939cddc455a29e5111527cd16f8 Mon Sep 17 00:00:00 2001 From: Hiroshi Ioka Date: Sat, 26 Dec 2015 16:50:01 +0900 Subject: [PATCH 068/267] os/exec: cleanup and remove duplicated code Change-Id: Ia2f61427b1cc09064ac4c0563bccbd9b98767a0e Reviewed-on: https://go-review.googlesource.com/18118 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/os/exec/lp_plan9.go | 8 ++-- src/os/exec/lp_unix.go | 10 ++--- src/os/exec/lp_windows.go | 69 ++++++++++------------------------ src/os/exec/lp_windows_test.go | 2 +- 4 files changed, 29 insertions(+), 60 deletions(-) diff --git a/src/os/exec/lp_plan9.go b/src/os/exec/lp_plan9.go index 82678802a96483..142f87ed32b3b5 100644 --- a/src/os/exec/lp_plan9.go +++ b/src/os/exec/lp_plan9.go @@ -7,6 +7,7 @@ package exec import ( "errors" "os" + "path/filepath" "strings" ) @@ -44,9 +45,10 @@ func LookPath(file string) (string, error) { } path := os.Getenv("path") - for _, dir := range strings.Split(path, "\000") { - if err := findExecutable(dir + "/" + file); err == nil { - return dir + "/" + file, nil + for _, dir := range filepath.SplitList(path) { + path := filepath.Join(dir, file) + if err := findExecutable(path); err == nil { + return path, nil } } return "", &Error{file, ErrNotFound} diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go index 32e3046cb87401..7a302752a8974d 100644 --- a/src/os/exec/lp_unix.go +++ b/src/os/exec/lp_unix.go @@ -9,6 +9,7 @@ package exec import ( "errors" "os" + "path/filepath" "strings" ) @@ -42,16 +43,13 @@ func LookPath(file string) (string, error) { } return "", &Error{file, err} } - pathenv := os.Getenv("PATH") - if pathenv == "" { - return "", &Error{file, ErrNotFound} - } - for _, dir := range strings.Split(pathenv, ":") { + path := os.Getenv("PATH") + for _, dir := range filepath.SplitList(path) { if dir == "" { // Unix shell semantics: path element "" means "." dir = "." } - path := dir + "/" + file + path := filepath.Join(dir, file) if err := findExecutable(path); err == nil { return path, nil } diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go index 1c005220d01bc3..793d4d98b3a6ae 100644 --- a/src/os/exec/lp_windows.go +++ b/src/os/exec/lp_windows.go @@ -7,6 +7,7 @@ package exec import ( "errors" "os" + "path/filepath" "strings" ) @@ -56,20 +57,22 @@ func findExecutable(file string, exts []string) (string, error) { // a suitable candidate. // The result may be an absolute path or a path relative to the current directory. func LookPath(file string) (string, error) { + var exts []string x := os.Getenv(`PATHEXT`) - if x == "" { - x = `.COM;.EXE;.BAT;.CMD` - } - exts := []string{} - for _, e := range strings.Split(strings.ToLower(x), `;`) { - if e == "" { - continue - } - if e[0] != '.' { - e = "." + e + if x != "" { + for _, e := range strings.Split(strings.ToLower(x), `;`) { + if e == "" { + continue + } + if e[0] != '.' { + e = "." + e + } + exts = append(exts, e) } - exts = append(exts, e) + } else { + exts = []string{".com", ".exe", ".bat", ".cmd"} } + if strings.ContainsAny(file, `:\/`) { if f, err := findExecutable(file, exts); err == nil { return f, nil @@ -77,48 +80,14 @@ func LookPath(file string) (string, error) { return "", &Error{file, err} } } - if f, err := findExecutable(`.\`+file, exts); err == nil { + if f, err := findExecutable(filepath.Join(".", file), exts); err == nil { return f, nil } - if pathenv := os.Getenv(`PATH`); pathenv != "" { - for _, dir := range splitList(pathenv) { - if f, err := findExecutable(dir+`\`+file, exts); err == nil { - return f, nil - } + path := os.Getenv("path") + for _, dir := range filepath.SplitList(path) { + if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil { + return f, nil } } return "", &Error{file, ErrNotFound} } - -func splitList(path string) []string { - // The same implementation is used in SplitList in path/filepath; - // consider changing path/filepath when changing this. - - if path == "" { - return []string{} - } - - // Split path, respecting but preserving quotes. - list := []string{} - start := 0 - quo := false - for i := 0; i < len(path); i++ { - switch c := path[i]; { - case c == '"': - quo = !quo - case c == os.PathListSeparator && !quo: - list = append(list, path[start:i]) - start = i + 1 - } - } - list = append(list, path[start:]) - - // Remove quotes. - for i, s := range list { - if strings.Contains(s, `"`) { - list[i] = strings.Replace(s, `"`, "", -1) - } - } - - return list -} diff --git a/src/os/exec/lp_windows_test.go b/src/os/exec/lp_windows_test.go index 042e5a1389eb7d..96a22d843f8544 100644 --- a/src/os/exec/lp_windows_test.go +++ b/src/os/exec/lp_windows_test.go @@ -107,7 +107,7 @@ func createEnv(dir, PATH, PATHEXT string) []string { env := os.Environ() env = updateEnv(env, "PATHEXT", PATHEXT) // Add dir in front of every directory in the PATH. - dirs := splitList(PATH) + dirs := filepath.SplitList(PATH) for i := range dirs { dirs[i] = filepath.Join(dir, dirs[i]) } From 9a57fa31ff35024b9f628e7eae39bfd35bf90d77 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 10 May 2016 16:09:16 -0700 Subject: [PATCH 069/267] net/http: document ResponseWriter read-vs-write concurrency rules Summary: Go's HTTP/1.x server closes the request body once writes are flushed. Go's HTTP/2 server supports concurrent read & write. Added a TODO to make the HTTP/1.x server also support concurrent read+write. But for now, document it. Updates #15527 Change-Id: I81f7354923d37bfc1632629679c75c06a62bb584 Reviewed-on: https://go-review.googlesource.com/23011 Reviewed-by: Andrew Gerrand --- src/net/http/server.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index 23fb84fcdabf41..e24777421cf341 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -91,10 +91,24 @@ type ResponseWriter interface { Header() Header // Write writes the data to the connection as part of an HTTP reply. - // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) - // before writing the data. If the Header does not contain a - // Content-Type line, Write adds a Content-Type set to the result of passing - // the initial 512 bytes of written data to DetectContentType. + // + // If WriteHeader has not yet been called, Write calls + // WriteHeader(http.StatusOK) before writing the data. If the Header + // does not contain a Content-Type line, Write adds a Content-Type set + // to the result of passing the initial 512 bytes of written data to + // DetectContentType. + // + // Depending on the HTTP protocol version and the client, calling + // Write or WriteHeader may prevent future reads on the + // Request.Body. For HTTP/1.x requests, handlers should read any + // needed request body data before writing the response. Once the + // headers have been flushed (due to either an explicit Flusher.Flush + // call or writing enough data to trigger a flush), the request body + // may be unavailable. For HTTP/2 requests, the Go HTTP server permits + // handlers to continue to read the request body while concurrently + // writing the response. However, such behavior may not be supported + // by all HTTP/2 clients. Handlers should read before writing if + // possible to maximize compatibility. Write([]byte) (int, error) // WriteHeader sends an HTTP response header with status code. @@ -1027,6 +1041,9 @@ func (cw *chunkWriter) writeHeader(p []byte) { // replying, if the handler hasn't already done so. But we // don't want to do an unbounded amount of reading here for // DoS reasons, so we only try up to a threshold. + // TODO(bradfitz): where does RFC 2616 say that? See Issue 15527 + // about HTTP/1.x Handlers concurrently reading and writing, like + // HTTP/2 handlers can do. Maybe this code should be relaxed? if w.req.ContentLength != 0 && !w.closeAfterReply { var discard, tooBig bool From 20e362dae73b84e7b9dba9959444e5bc9d513ff1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 May 2016 09:37:46 -0700 Subject: [PATCH 070/267] cmd/cgo: remove //extern for check functions in gccgo Go prologue The //extern comments are incorrect and cause undefined symbol errorswhen building cgo code with -compiler=gccgo. The code is already designed to use weak references, and that support relies on the cgo check functions being treated as local functions. Change-Id: Ib38a640cc4ce6eba74cfbf41ba7147ec88769ec0 Reviewed-on: https://go-review.googlesource.com/23014 Run-TryBot: Ian Lance Taylor Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/cgo/out.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 5eab3a71b49e29..265a3bbe6f71c4 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -1360,10 +1360,8 @@ func _cgoCheckResult(interface{}) ` const gccgoGoProlog = ` -//extern runtime.cgoCheckPointer func _cgoCheckPointer(interface{}, ...interface{}) interface{} -//extern runtime.cgoCheckResult func _cgoCheckResult(interface{}) ` From 4d8031cf3c179d8682b62feae1d5a9109d14b382 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 10 May 2016 15:09:23 -0700 Subject: [PATCH 071/267] net/http: make the MaxBytesReader.Read error sticky Fixes #14981 Change-Id: I39b906d119ca96815801a0fbef2dbe524a3246ff Reviewed-on: https://go-review.googlesource.com/23009 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/request.go | 90 ++++++++++++++++-------------------- src/net/http/request_test.go | 40 ++++++++++++++++ 2 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 1bde114909c38e..45507d23d14beb 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -885,68 +885,56 @@ func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser { } type maxBytesReader struct { - w ResponseWriter - r io.ReadCloser // underlying reader - n int64 // max bytes remaining - stopped bool - sawEOF bool + w ResponseWriter + r io.ReadCloser // underlying reader + n int64 // max bytes remaining + err error // sticky error } func (l *maxBytesReader) tooLarge() (n int, err error) { - if !l.stopped { - l.stopped = true - - // The server code and client code both use - // maxBytesReader. This "requestTooLarge" check is - // only used by the server code. To prevent binaries - // which only using the HTTP Client code (such as - // cmd/go) from also linking in the HTTP server, don't - // use a static type assertion to the server - // "*response" type. Check this interface instead: - type requestTooLarger interface { - requestTooLarge() - } - if res, ok := l.w.(requestTooLarger); ok { - res.requestTooLarge() - } - } - return 0, errors.New("http: request body too large") + l.err = errors.New("http: request body too large") + return 0, l.err } func (l *maxBytesReader) Read(p []byte) (n int, err error) { - toRead := l.n - if l.n == 0 { - if l.sawEOF { - return l.tooLarge() - } - // The underlying io.Reader may not return (0, io.EOF) - // at EOF if the requested size is 0, so read 1 byte - // instead. The io.Reader docs are a bit ambiguous - // about the return value of Read when 0 bytes are - // requested, and {bytes,strings}.Reader gets it wrong - // too (it returns (0, nil) even at EOF). - toRead = 1 + if l.err != nil { + return 0, l.err + } + if len(p) == 0 { + return 0, nil } - if int64(len(p)) > toRead { - p = p[:toRead] + // If they asked for a 32KB byte read but only 5 bytes are + // remaining, no need to read 32KB. 6 bytes will answer the + // question of the whether we hit the limit or go past it. + if int64(len(p)) > l.n+1 { + p = p[:l.n+1] } n, err = l.r.Read(p) - if err == io.EOF { - l.sawEOF = true - } - if l.n == 0 { - // If we had zero bytes to read remaining (but hadn't seen EOF) - // and we get a byte here, that means we went over our limit. - if n > 0 { - return l.tooLarge() - } - return 0, err + + if int64(n) <= l.n { + l.n -= int64(n) + l.err = err + return n, err } - l.n -= int64(n) - if l.n < 0 { - l.n = 0 + + n = int(l.n) + l.n = 0 + + // The server code and client code both use + // maxBytesReader. This "requestTooLarge" check is + // only used by the server code. To prevent binaries + // which only using the HTTP Client code (such as + // cmd/go) from also linking in the HTTP server, don't + // use a static type assertion to the server + // "*response" type. Check this interface instead: + type requestTooLarger interface { + requestTooLarge() } - return + if res, ok := l.w.(requestTooLarger); ok { + res.requestTooLarge() + } + l.err = errors.New("http: request body too large") + return n, l.err } func (l *maxBytesReader) Close() error { diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 82c7af3cda8dbe..a4c88c02915ccd 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -679,6 +679,46 @@ func TestIssue10884_MaxBytesEOF(t *testing.T) { } } +// Issue 14981: MaxBytesReader's return error wasn't sticky. It +// doesn't technically need to be, but people expected it to be. +func TestMaxBytesReaderStickyError(t *testing.T) { + isSticky := func(r io.Reader) error { + var log bytes.Buffer + buf := make([]byte, 1000) + var firstErr error + for { + n, err := r.Read(buf) + fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err) + if err == nil { + continue + } + if firstErr == nil { + firstErr = err + continue + } + if !reflect.DeepEqual(err, firstErr) { + return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes()) + } + t.Logf("Got log: %s", log.Bytes()) + return nil + } + } + tests := [...]struct { + readable int + limit int64 + }{ + 0: {99, 100}, + 1: {100, 100}, + 2: {101, 100}, + } + for i, tt := range tests { + rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit) + if err := isSticky(rc); err != nil { + t.Errorf("%d. error: %v", i, err) + } + } +} + func testMissingFile(t *testing.T, req *Request) { f, fh, err := req.FormFile("missing") if f != nil { From 2ffb3e5d905b5622204d199128dec06cefd57790 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Ruel Date: Thu, 7 Apr 2016 14:24:24 -0400 Subject: [PATCH 072/267] os: fix Remove for file with read only attribute on Windows Include integration test. Confirmed that without the fix, the test case TestDeleteReadOnly fails. This permits to revert "cmd/go: reset read-only flag during TestIssue10952" This reverts commit 3b7841b3aff9204f054ffabbe4dd39d3e3dd3e91. Fixes #9606 Change-Id: Ib55c151a8cf1a1da02ab18c34a9b58f615c34254 Reviewed-on: https://go-review.googlesource.com/18235 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/go/go_test.go | 28 ---------------------------- src/os/file_windows.go | 6 ++++++ src/os/os_windows_test.go | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index ac82b2ffeb467b..b6673967619374 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -580,32 +580,6 @@ func (tg *testgoData) cleanup() { } } -// resetReadOnlyFlagAll resets windows read-only flag -// set on path and any children it contains. -// The flag is set by git and has to be removed. -// os.Remove refuses to remove files with read-only flag set. -func (tg *testgoData) resetReadOnlyFlagAll(path string) { - fi, err := os.Stat(path) - if err != nil { - tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) - } - if !fi.IsDir() { - err := os.Chmod(path, 0666) - if err != nil { - tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) - } - } - fd, err := os.Open(path) - if err != nil { - tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) - } - defer fd.Close() - names, _ := fd.Readdirnames(-1) - for _, name := range names { - tg.resetReadOnlyFlagAll(path + string(filepath.Separator) + name) - } -} - // failSSH puts an ssh executable in the PATH that always fails. // This is to stub out uses of ssh by go get. func (tg *testgoData) failSSH() { @@ -1192,7 +1166,6 @@ func TestIssue10952(t *testing.T) { const importPath = "github.com/zombiezen/go-get-issue-10952" tg.run("get", "-d", "-u", importPath) repoDir := tg.path("src/" + importPath) - defer tg.resetReadOnlyFlagAll(repoDir) tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git") tg.run("get", "-d", "-u", importPath) } @@ -1216,7 +1189,6 @@ func TestGetGitDefaultBranch(t *testing.T) { tg.run("get", "-d", importPath) repoDir := tg.path("src/" + importPath) - defer tg.resetReadOnlyFlagAll(repoDir) tg.runGit(repoDir, "branch", "--contains", "HEAD") tg.grepStdout(`\* another-branch`, "not on correct default branch") diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 08aff83a77510c..f470fc4315cc2b 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -474,6 +474,12 @@ func Remove(name string) error { } else { if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { e = e1 + } else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 { + if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil { + if e = syscall.DeleteFile(p); e == nil { + return nil + } + } } } } diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 2f7d48d5bdf06c..05d7a8f34e9a9f 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -223,3 +223,25 @@ func TestOpenVolumeName(t *testing.T) { t.Fatalf("unexpected file list %q, want %q", have, want) } } + +func TestDeleteReadOnly(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "TestDeleteReadOnly") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + p := filepath.Join(tmpdir, "a") + // This sets FILE_ATTRIBUTE_READONLY. + f, err := os.OpenFile(p, os.O_CREATE, 0400) + if err != nil { + t.Fatal(err) + } + f.Close() + + if err = os.Chmod(p, 0400); err != nil { + t.Fatal(err) + } + if err = os.Remove(p); err != nil { + t.Fatal(err) + } +} From e9407ae514df7d18e162ce03ebd530fe21aed16d Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 11 May 2016 10:23:37 -0700 Subject: [PATCH 073/267] cmd/pprof: remove tempDir when no longer needed The pprof tools properly cleans up all files it creates, but forgets to clean up the temporary directory itself. This CL fixes that. Fixes #13863 Change-Id: I1151c36cdad5ace7cc97e7e04001cf0149ef0f63 Reviewed-on: https://go-review.googlesource.com/23019 Reviewed-by: Brad Fitzpatrick Run-TryBot: Joe Tsai TryBot-Result: Gobot Gobot --- src/cmd/internal/pprof/commands/commands.go | 1 + src/cmd/internal/pprof/tempfile/tempfile.go | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/internal/pprof/commands/commands.go b/src/cmd/internal/pprof/commands/commands.go index 5018c02af185e7..5dfbbd4a5dc8ac 100644 --- a/src/cmd/internal/pprof/commands/commands.go +++ b/src/cmd/internal/pprof/commands/commands.go @@ -197,6 +197,7 @@ func makeVizTmpDir() error { if err != nil { return err } + tempfile.DeferDelete(name) vizTmpDir = name return nil } diff --git a/src/cmd/internal/pprof/tempfile/tempfile.go b/src/cmd/internal/pprof/tempfile/tempfile.go index 31c117690a1c1f..a5706345e43954 100644 --- a/src/cmd/internal/pprof/tempfile/tempfile.go +++ b/src/cmd/internal/pprof/tempfile/tempfile.go @@ -27,18 +27,19 @@ func New(dir, prefix, suffix string) (*os.File, error) { var tempFiles []string var tempFilesMu = sync.Mutex{} -// DeferDelete marks a file to be deleted by next call to Cleanup() +// DeferDelete marks a file or directory to be deleted by next call to Cleanup. func DeferDelete(path string) { tempFilesMu.Lock() tempFiles = append(tempFiles, path) tempFilesMu.Unlock() } -// Cleanup removes any temporary files selected for deferred cleaning. +// Cleanup removes any temporary files or directories selected for deferred cleaning. +// Similar to defer semantics, the nodes are deleted in LIFO order. func Cleanup() { tempFilesMu.Lock() - for _, f := range tempFiles { - os.Remove(f) + for i := len(tempFiles) - 1; i >= 0; i-- { + os.Remove(tempFiles[i]) } tempFiles = nil tempFilesMu.Unlock() From aff4889089f970fb739acf5e3a5bddd3491a908b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 May 2016 11:28:36 -0700 Subject: [PATCH 074/267] cmd/compile: clean up encoding of method expressions and add test Fixes #15646. Change-Id: Ic13d1adc0a358149209195cdb03811eeee506fb8 Reviewed-on: https://go-review.googlesource.com/23052 TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/bexport.go | 22 ++++++++++------------ src/cmd/compile/internal/gc/bimport.go | 11 +++-------- test/fixedbugs/issue15646.dir/a.go | 23 +++++++++++++++++++++++ test/fixedbugs/issue15646.dir/b.go | 16 ++++++++++++++++ test/fixedbugs/issue15646.go | 9 +++++++++ 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 test/fixedbugs/issue15646.dir/a.go create mode 100644 test/fixedbugs/issue15646.dir/b.go create mode 100644 test/fixedbugs/issue15646.go diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index cd2963e8e64e09..3fe729618b4885 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1157,9 +1157,9 @@ func (p *exporter) expr(n *Node) { // Special case: name used as local variable in export. // _ becomes ~b%d internally; print as _ for export if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { - // case 0: mapped to ONAME - p.op(ONAME) - p.bool(true) // indicate blank identifier + // case 0: mapped to OPACK + p.op(OPACK) + p.string("_") // inlined and customized version of p.sym(n) break } @@ -1174,22 +1174,18 @@ func (p *exporter) expr(n *Node) { // but for export, this should be rendered as (*pkg.T).meth. // These nodes have the special property that they are names with a left OTYPE and a right ONAME. if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { - // case 2: mapped to ONAME - p.op(ONAME) - // TODO(gri) can we map this case directly to OXDOT - // and then get rid of the bool here? - p.bool(false) // indicate non-blank identifier - p.typ(n.Left.Type) + // case 2: mapped to OXDOT + p.op(OXDOT) + p.expr(n.Left) // n.Left.Op == OTYPE p.fieldSym(n.Right.Sym, true) break } // case 3: mapped to OPACK - p.op(OPACK) - p.sym(n) // fallthrough inlined here + fallthrough case OPACK, ONONAME: - p.op(op) + p.op(OPACK) p.sym(n) case OTYPE: @@ -1508,6 +1504,8 @@ func (p *exporter) fieldSym(s *Sym, short bool) { } } +// sym must encode the _ (blank) identifier as a single string "_" since +// encoding for some nodes is based on this assumption (e.g. ONAME nodes). func (p *exporter) sym(n *Node) { s := n.Sym if s.Pkg != nil { diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index cb375a0ac3fd5b..c161c4ffb10c93 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -798,15 +798,10 @@ func (p *importer) node() *Node { } return n - case ONAME: - if p.bool() { - // "_" - // TODO(gri) avoid repeated "_" lookup - return mkname(Pkglookup("_", localpkg)) - } - return NodSym(OXDOT, typenod(p.typ()), p.fieldSym()) + // case ONAME, OPACK, ONONAME: + // unreachable - mapped to case OPACK below by exporter - case OPACK, ONONAME: + case OPACK: return mkname(p.sym()) case OTYPE: diff --git a/test/fixedbugs/issue15646.dir/a.go b/test/fixedbugs/issue15646.dir/a.go new file mode 100644 index 00000000000000..842f19685fd282 --- /dev/null +++ b/test/fixedbugs/issue15646.dir/a.go @@ -0,0 +1,23 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T struct{} + +func (T) m() string { + return "m" +} + +func (*T) mp() string { + return "mp" +} + +func F() func(T) string { + return T.m // method expression +} + +func Fp() func(*T) string { + return (*T).mp // method expression +} diff --git a/test/fixedbugs/issue15646.dir/b.go b/test/fixedbugs/issue15646.dir/b.go new file mode 100644 index 00000000000000..3d011ba30195b8 --- /dev/null +++ b/test/fixedbugs/issue15646.dir/b.go @@ -0,0 +1,16 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" // import must succeed + +func main() { + if a.F()(a.T{}) != "m" { + panic(0) + } + if a.Fp()(nil) != "mp" { + panic(1) + } +} diff --git a/test/fixedbugs/issue15646.go b/test/fixedbugs/issue15646.go new file mode 100644 index 00000000000000..cd4ba9d4e52035 --- /dev/null +++ b/test/fixedbugs/issue15646.go @@ -0,0 +1,9 @@ +// rundir + +// 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. + +// Test that method expressions are correctly encoded +// in binary export data and can be imported again. +package ignore \ No newline at end of file From ef62f641c37431a870fa093c43b3ee51a06db0da Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 May 2016 12:40:17 -0700 Subject: [PATCH 075/267] cmd/compile: use ONAME instead of OPACK in binary export format This is addressing feedback given on golang.org/cl/23052; we do it in a separate CL to separate the functional from the rename change. ONAME was not used in the export data, but it's the natural node op where we used OPACK instead. Renamed. Furthermore, OPACK and ONONAME nodes are replaced by the type checker with ONAME nodes, so OPACK nodes cannot occur when exporting type-checked code. Removed a special-case for OPACK nodes since they don't appear. Change-Id: I78b01a1badbf60e9283eaadeca2578a65d28cbd2 Reviewed-on: https://go-review.googlesource.com/23053 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/bexport.go | 21 +++++++-------------- src/cmd/compile/internal/gc/bimport.go | 17 +++++------------ 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 3fe729618b4885..48b2b201562cab 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1157,15 +1157,13 @@ func (p *exporter) expr(n *Node) { // Special case: name used as local variable in export. // _ becomes ~b%d internally; print as _ for export if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { - // case 0: mapped to OPACK - p.op(OPACK) + p.op(ONAME) p.string("_") // inlined and customized version of p.sym(n) break } if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 { - // case 1: mapped to OPACK - p.op(OPACK) + p.op(ONAME) p.sym(n) break } @@ -1174,20 +1172,18 @@ func (p *exporter) expr(n *Node) { // but for export, this should be rendered as (*pkg.T).meth. // These nodes have the special property that they are names with a left OTYPE and a right ONAME. if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { - // case 2: mapped to OXDOT p.op(OXDOT) p.expr(n.Left) // n.Left.Op == OTYPE p.fieldSym(n.Right.Sym, true) break } - // case 3: mapped to OPACK - fallthrough - - case OPACK, ONONAME: - p.op(OPACK) + p.op(ONAME) p.sym(n) + // case OPACK, ONONAME: + // should have been resolved by typechecking - handled by default case + case OTYPE: p.op(OTYPE) if p.bool(n.Type == nil) { @@ -1400,10 +1396,7 @@ func (p *exporter) stmt(n *Node) { p.expr(n.Right) } - case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: - fallthrough - - case OAS2: + case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: p.op(OAS2) p.exprList(n.List) p.exprList(n.Rlist) diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index c161c4ffb10c93..1bc184f7a43070 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -798,12 +798,12 @@ func (p *importer) node() *Node { } return n - // case ONAME, OPACK, ONONAME: - // unreachable - mapped to case OPACK below by exporter - - case OPACK: + case ONAME: return mkname(p.sym()) + // case OPACK, ONONAME: + // unreachable - should have been resolved by typechecking + case OTYPE: if p.bool() { return mkname(p.sym()) @@ -854,14 +854,7 @@ func (p *importer) node() *Node { case OXDOT: // see parser.new_dotname - obj := p.expr() - sel := p.fieldSym() - if obj.Op == OPACK { - s := restrictlookup(sel.Name, obj.Name.Pkg) - obj.Used = true - return oldname(s) - } - return NodSym(OXDOT, obj, sel) + return NodSym(OXDOT, p.expr(), p.fieldSym()) // case ODOTTYPE, ODOTTYPE2: // unreachable - mapped to case ODOTTYPE below by exporter From 114051aa1d5da5dec1b2707b1403261a3135b9b5 Mon Sep 17 00:00:00 2001 From: Johan Sageryd Date: Sun, 8 May 2016 18:06:03 +0200 Subject: [PATCH 076/267] text/template: fix typo in documentation Change-Id: I4ccfaa16e153aad001d670891b3848264e63cf6f Reviewed-on: https://go-review.googlesource.com/23031 Reviewed-by: Brad Fitzpatrick --- src/text/template/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text/template/doc.go b/src/text/template/doc.go index df8c95f8c8949e..48e9aa7395cec9 100644 --- a/src/text/template/doc.go +++ b/src/text/template/doc.go @@ -220,7 +220,7 @@ value (argument) or a function or method call, possibly with multiple arguments: Functions and function names are described below. A pipeline may be "chained" by separating a sequence of commands with pipeline -characters '|'. In a chained pipeline, the result of the each command is +characters '|'. In a chained pipeline, the result of each command is passed as the last argument of the following command. The output of the final command in the pipeline is the value of the pipeline. From eb9062b7bf77a5051b3db6f3e944739a486ca1e4 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 11 May 2016 15:01:28 -0700 Subject: [PATCH 077/267] net/http: keep HTTP/1.0 keep-alive conns open if response can't have a body Fixes #15647 Change-Id: I588bfa4eb336d1da1fcda8d06e32ed13c0b51c70 Reviewed-on: https://go-review.googlesource.com/23061 Run-TryBot: Brad Fitzpatrick Reviewed-by: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/net/http/serve_test.go | 43 ++++++++++++++++++++++++++++++++++++++ src/net/http/server.go | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index b34875f061a062..95983e4b02e756 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -714,6 +714,31 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) { } } +func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) { + defer afterTest(t) + ts := httptest.NewServer(handler) + defer ts.Close() + conn, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + br := bufio.NewReader(conn) + for i := 0; i < 2; i++ { + if _, err := io.WriteString(conn, req); err != nil { + t.Fatal(err) + } + res, err := ReadResponse(br, nil) + if err != nil { + t.Fatalf("res %d: %v", i+1, err) + } + if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + t.Fatalf("res %d body copy: %v", i+1, err) + } + res.Body.Close() + } +} + // TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive. func TestServeHTTP10Close(t *testing.T) { testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { @@ -749,6 +774,24 @@ func TestHTTP2UpgradeClosesConnection(t *testing.T) { })) } +func send204(w ResponseWriter, r *Request) { w.WriteHeader(204) } +func send304(w ResponseWriter, r *Request) { w.WriteHeader(304) } + +// Issue 15647: 204 responses can't have bodies, so HTTP/1.0 keep-alive conns should stay open. +func TestHTTP10KeepAlive204Response(t *testing.T) { + testTCPConnectionStaysOpen(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(send204)) +} + +func TestHTTP11KeepAlive204Response(t *testing.T) { + testTCPConnectionStaysOpen(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n", HandlerFunc(send204)) +} + +func TestHTTP10KeepAlive304Response(t *testing.T) { + testTCPConnectionStaysOpen(t, + "GET / HTTP/1.0\r\nConnection: keep-alive\r\nIf-Modified-Since: Mon, 02 Jan 2006 15:04:05 GMT\r\n\r\n", + HandlerFunc(send304)) +} + func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) } func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) } diff --git a/src/net/http/server.go b/src/net/http/server.go index e24777421cf341..d0be7d01dbd0aa 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1008,7 +1008,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { // Check for a explicit (and valid) Content-Length header. hasCL := w.contentLength != -1 - if w.wants10KeepAlive && (isHEAD || hasCL) { + if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) { _, connectionHeaderSet := header["Connection"] if !connectionHeaderSet { setHeader.connection = "keep-alive" From 21d781070cea6001ee541933ed76dc6da96bde4c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 May 2016 13:39:36 -0700 Subject: [PATCH 078/267] cmd/compile: use one format for exporting calls of builtin functions Minor cleanup. Each of these cases appears both during export and import when running all.bash and thus is tested by all.bash. Change-Id: Iaa4a5a5b163cefe33e43d08d396e02a02e5c22a5 Reviewed-on: https://go-review.googlesource.com/23060 Reviewed-by: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/bexport.go | 17 +++++++++++++---- src/cmd/compile/internal/gc/bimport.go | 19 ++++--------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 48b2b201562cab..2e5731e2b8c580 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1256,26 +1256,35 @@ func (p *exporter) expr(n *Node) { p.expr(max) case OCOPY, OCOMPLEX: + // treated like other builtin calls (see e.g., OREAL) p.op(op) p.expr(n.Left) p.expr(n.Right) + p.op(OEND) case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: p.op(OCONV) p.typ(n.Type) - if p.bool(n.Left != nil) { + if n.Left != nil { p.expr(n.Left) + p.op(OEND) } else { - p.exprList(n.List) + p.exprList(n.List) // emits terminating OEND } case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: p.op(op) - if p.bool(n.Left != nil) { + if n.Left != nil { p.expr(n.Left) + p.op(OEND) } else { - p.exprList(n.List) + p.exprList(n.List) // emits terminating OEND + } + // only append() calls may contain '...' arguments + if op == OAPPEND { p.bool(n.Isddd) + } else if n.Isddd { + Fatalf("exporter: unexpected '...' with %s call", opnames[op]) } case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index 1bc184f7a43070..51847538961eec 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -884,29 +884,18 @@ func (p *importer) node() *Node { n.SetSliceBounds(low, high, max) return n - case OCOPY, OCOMPLEX: - n := builtinCall(op) - n.List.Set([]*Node{p.expr(), p.expr()}) - return n - // case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: // unreachable - mapped to OCONV case below by exporter case OCONV: n := Nod(OCALL, typenod(p.typ()), nil) - if p.bool() { - n.List.Set1(p.expr()) - } else { - n.List.Set(p.exprList()) - } + n.List.Set(p.exprList()) return n - case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: + case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: n := builtinCall(op) - if p.bool() { - n.List.Set1(p.expr()) - } else { - n.List.Set(p.exprList()) + n.List.Set(p.exprList()) + if op == OAPPEND { n.Isddd = p.bool() } return n From 81b70f3751374ccd1eda2f536156dd91cd9f9c9b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 11 May 2016 16:16:37 +1000 Subject: [PATCH 079/267] syscall: make mksyscall_windows.go -systemdll flag true by default Updates #15167 Change-Id: I826f67e75011ba79325a1294ac0d70d7c6a3e32f Reviewed-on: https://go-review.googlesource.com/23022 Reviewed-by: Brad Fitzpatrick Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot --- src/internal/syscall/windows/registry/syscall.go | 2 +- src/internal/syscall/windows/syscall_windows.go | 2 +- src/syscall/mksyscall_windows.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go index 02d985cec90b0f..5426cae9096330 100644 --- a/src/internal/syscall/windows/registry/syscall.go +++ b/src/internal/syscall/windows/registry/syscall.go @@ -8,7 +8,7 @@ package registry import "syscall" -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall.go +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go const ( _REG_OPTION_NON_VOLATILE = 0 diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index 2eae5e75f9e411..7b2bc79cebe4a4 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -6,7 +6,7 @@ package windows import "syscall" -//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall_windows.go +//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index 4ccbb04908c7a5..84747962ab559e 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -68,7 +68,7 @@ import ( var ( filename = flag.String("output", "", "output file name (standard output if omitted)") printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall") - systemDLL = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory") + systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory") ) func trim(s string) string { From 5bd37b8e78980beed2861bbdc7f8f28fc3f72671 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 9 May 2016 02:13:03 +1000 Subject: [PATCH 080/267] runtime: stop using sigreturn on openbsd/386 In future releases of OpenBSD, the sigreturn syscall will no longer exist. As such, stop using sigreturn on openbsd/386 and just return from the signal trampoline (as we already do for openbsd/amd64 and openbsd/arm). Change-Id: Ic4de1795bbfbfb062a685832aea0d597988c6985 Reviewed-on: https://go-review.googlesource.com/23024 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/sys_openbsd_386.s | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s index f80a85fb67767b..2bb818f456ea2e 100644 --- a/src/runtime/sys_openbsd_386.s +++ b/src/runtime/sys_openbsd_386.s @@ -214,14 +214,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12 MOVL context+8(FP), BX MOVL BX, 8(SP) CALL runtime·sigtrampgo(SB) - - // call sigreturn - MOVL context+8(FP), AX - MOVL $0, 0(SP) // syscall gap - MOVL AX, 4(SP) // arg 1 - sigcontext - MOVL $103, AX // sys_sigreturn - INT $0x80 - MOVL $0xf1, 0xf1 // crash RET // int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void)); From a71584975dedd4f4975d65047ec7660191a49613 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 12 May 2016 15:00:10 +0300 Subject: [PATCH 081/267] reflect: fix vet warnings Updated #11041 Change-Id: I4a110ba8fefb367a1049b4a65dd20c39eb890ea2 Reviewed-on: https://go-review.googlesource.com/23080 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/reflect/all_test.go | 8 ++++---- src/reflect/type.go | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 1a7952d7892d83..5beec63273b526 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4210,7 +4210,7 @@ func TestStructOfExportRules(t *testing.T) { } exported := isExported(n) if exported != test.exported { - t.Errorf("test-%d: got exported=%v want exported=%v", exported, test.exported) + t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported) } }) } @@ -4520,7 +4520,7 @@ func TestStructOfWithInterface(t *testing.T) { if table.impl { t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ) } else { - t.Errorf("test-%d: type=%v should NOT implement Iface\n", table.typ) + t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ) } continue } @@ -4748,7 +4748,7 @@ func TestFuncOf(t *testing.T) { if len(args) != 1 { t.Errorf("args == %v, want exactly one arg", args) } else if args[0].Type() != TypeOf(K("")) { - t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K(""))) + t.Errorf("args[0] is type %v, want %v", args[0].Type(), TypeOf(K(""))) } else if args[0].String() != "gopher" { t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher") } @@ -4760,7 +4760,7 @@ func TestFuncOf(t *testing.T) { if len(outs) != 1 { t.Fatalf("v.Call returned %v, want exactly one result", outs) } else if outs[0].Type() != TypeOf(V(0)) { - t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0))) + t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type(), TypeOf(V(0))) } f := outs[0].Float() if f != 3.14 { diff --git a/src/reflect/type.go b/src/reflect/type.go index b499d01a2c7346..5c6e3d55009d7e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2758,7 +2758,6 @@ func typeptrdata(t *rtype) uintptr { default: panic("reflect.typeptrdata: unexpected type, " + t.String()) } - return 0 } // See cmd/compile/internal/gc/reflect.go for derivation of constant. From 376e6415402b4e62f96fb7f8f7a99d352aa9c1b3 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 12 May 2016 15:13:22 +0300 Subject: [PATCH 082/267] cmd: fixed certain vet warnings Updates #11041 Change-Id: I7f2583d08f344d6622027c5e8a5de1f5d2f2881c Reviewed-on: https://go-review.googlesource.com/23082 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/cover/cover.go | 2 +- src/cmd/dist/test.go | 2 +- src/cmd/internal/pprof/report/report.go | 4 +++- src/cmd/link/internal/ld/objfile.go | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go index 46495950e98f53..a9ed66eea06cd5 100644 --- a/src/cmd/cover/cover.go +++ b/src/cmd/cover/cover.go @@ -388,7 +388,7 @@ func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup { } } if list != nil { - comments = append(comments, &ast.CommentGroup{list}) + comments = append(comments, &ast.CommentGroup{List: list}) } } return comments diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 3d123c2c8641da..1a1f7d961bea77 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -699,7 +699,7 @@ func (t *tester) supportedBuildmode(mode string) bool { } return false default: - log.Fatal("internal error: unknown buildmode %s", mode) + log.Fatalf("internal error: unknown buildmode %s", mode) return false } } diff --git a/src/cmd/internal/pprof/report/report.go b/src/cmd/internal/pprof/report/report.go index c492b752b96fbb..b11ad2ab3606e7 100644 --- a/src/cmd/internal/pprof/report/report.go +++ b/src/cmd/internal/pprof/report/report.go @@ -205,7 +205,9 @@ func nodesPerSymbol(ns nodes, symbols []*objSymbol) map[*objSymbol]nodes { // offset to adjust the sample addresses. func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes { // Add end marker to simplify printing loop. - insns = append(insns, plugin.Inst{^uint64(0), "", "", 0}) + insns = append(insns, plugin.Inst{ + Addr: ^uint64(0), + }) // Ensure samples are sorted by address. samples.sort(addressOrder) diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index d16431ddaa29ad..be9832dc454830 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -538,7 +538,7 @@ func (r *objReader) readSymName() string { origName = make([]byte, n) r.readFull(origName) } else if err != nil { - log.Fatalf("%s: error reading symbol: %v", err) + log.Fatalf("%s: error reading symbol: %v", r.pn, err) } adjName := r.rdBuf[:0] for { From e54dfc2ec4a057aa1bf06f9bef5cdb2e769a669d Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 12 May 2016 15:03:22 +0300 Subject: [PATCH 083/267] testing: fix vet warning Updates #11041 Change-Id: I32a381854e6a4fd791db380150efab57e6dfc38c Reviewed-on: https://go-review.googlesource.com/23081 Reviewed-by: Brad Fitzpatrick --- src/testing/match_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testing/match_test.go b/src/testing/match_test.go index d19036c72d1001..8c1c5f4452c5c0 100644 --- a/src/testing/match_test.go +++ b/src/testing/match_test.go @@ -135,8 +135,8 @@ func TestMatcher(t *T) { parent.level = 1 } if n, ok := m.fullName(parent, tc.sub); ok != tc.ok { - t.Errorf("pattern: %q, parent: %q, sub %q: got %v; want %v", - tc.pattern, tc.parent, tc.sub, ok, tc.ok, n) + t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v; want ok %v", + tc.pattern, tc.parent, tc.sub, n, ok, tc.ok) } } } From a8a2b38fb9e3886b6942621bf4b24ae062f0460b Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Thu, 12 May 2016 12:09:18 -0400 Subject: [PATCH 084/267] cmd/compile/internal/gc: minor cleanup of init.go comments Step 5 was deleted in f3575a9 however the numbering of the other steps wasn't adjusted accordingly. While we're here: clean up the whitespace, add curly braces where appropriate and delete semicolons. Change-Id: I4e77b2d3ee8460abe4bfb993674f83e35be8ff17 Reviewed-on: https://go-review.googlesource.com/23066 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/init.go | 39 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go index 6c9223b57a1b25..67a050a9cad136 100644 --- a/src/cmd/compile/internal/gc/init.go +++ b/src/cmd/compile/internal/gc/init.go @@ -31,21 +31,22 @@ func renameinit() *Sym { } // hand-craft the following initialization code -// var initdone· uint8 (1) -// func init() (2) +// var initdone· uint8 (1) +// func init() { (2) // if initdone· > 1 { (3) // return (3a) -// if initdone· == 1 { (4) -// throw(); (4a) -// } -// initdone· = 1; (6) -// // over all matching imported symbols -// .init() (7) -// { } (8) -// init.() // if any (9) -// initdone· = 2; (10) -// return (11) -// } +// } +// if initdone· == 1 { (4) +// throw() (4a) +// } +// initdone· = 1 (5) +// // over all matching imported symbols +// .init() (6) +// { } (7) +// init.() // if any (8) +// initdone· = 2 (9) +// return (10) +// } func anyinit(n []*Node) bool { // are there any interesting init statements for _, ln := range n { @@ -132,12 +133,12 @@ func fninit(n []*Node) { // (4a) b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil)) - // (6) + // (5) a = Nod(OAS, gatevar, Nodintconst(1)) r = append(r, a) - // (7) + // (6) for _, s := range initSyms { if s.Def != nil && s != initsym { // could check that it is fn of no args/returns @@ -146,10 +147,10 @@ func fninit(n []*Node) { } } - // (8) + // (7) r = append(r, nf...) - // (9) + // (8) // could check that it is fn of no args/returns for i := 1; ; i++ { s := LookupN("init.", i) @@ -160,12 +161,12 @@ func fninit(n []*Node) { r = append(r, a) } - // (10) + // (9) a = Nod(OAS, gatevar, Nodintconst(2)) r = append(r, a) - // (11) + // (10) a = Nod(ORETURN, nil, nil) r = append(r, a) From ccf2c019921999f49ba2ab8cbfe70ebecc986f46 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 12 May 2016 15:27:30 +0300 Subject: [PATCH 085/267] go/types: fix certain vet warnings Updates #11041 Change-Id: I4e1c670d2b7fc04927d77c6f933cee39b7d48b6e Reviewed-on: https://go-review.googlesource.com/23083 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/go/types/resolver.go | 2 +- src/go/types/stmt.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 1536df5bf1bebc..992188f0ff47b5 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -67,7 +67,7 @@ func (check *Checker) arityMatch(s, init *ast.ValueSpec) { // TODO(gri) avoid declared but not used error here } else { // init exprs "inherited" - check.errorf(s.Pos(), "extra init expr at %s", init.Pos()) + check.errorf(s.Pos(), "extra init expr at %s", check.fset.Position(init.Pos())) // TODO(gri) avoid declared but not used error here } case l > r && (init != nil || r != 1): diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index e301f711590ff4..5764430b1bf337 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -123,7 +123,7 @@ func (check *Checker) multipleDefaults(list []ast.Stmt) { } if d != nil { if first != nil { - check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos()) + check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos())) } else { first = d } From 7ae273923cdd5d00b72c293b57ade8a1e290a4a3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 3 May 2016 16:44:25 +0200 Subject: [PATCH 086/267] cmd/trace: split large traces into parts Trace viewer cannot handle traces larger than 256MB (limit on js string size): https://github.com/catapult-project/catapult/issues/627 And even that is problematic (chrome hangs and crashes). Split large traces into 100MB parts. Somewhat clumsy, but I don't see any other solution (other than rewriting trace viewer). At least it works reliably now. Fixes #15482 Change-Id: I993b5f43d22072c6f5bd041ab5888ce176f272b2 Reviewed-on: https://go-review.googlesource.com/22731 Reviewed-by: Hyang-Ah Hana Kim --- src/cmd/trace/main.go | 44 ++++++++++++++++---- src/cmd/trace/trace.go | 92 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 116 insertions(+), 20 deletions(-) diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go index 2735bf13ea23e9..893719edbf8fdc 100644 --- a/src/cmd/trace/main.go +++ b/src/cmd/trace/main.go @@ -22,7 +22,9 @@ import ( "bufio" "flag" "fmt" + "html/template" "internal/trace" + "log" "net" "net/http" "os" @@ -76,20 +78,36 @@ func main() { if err != nil { dief("failed to create server socket: %v\n", err) } - // Open browser. + + log.Printf("Parsing trace...") + events, err := parseEvents() + if err != nil { + dief("%v\n", err) + } + + log.Printf("Serializing trace...") + params := &traceParams{ + events: events, + endTime: int64(1<<63 - 1), + } + data := generateTrace(params) + + log.Printf("Splitting trace...") + ranges = splitTrace(data) + + log.Printf("Opening browser") if !startBrowser("http://" + ln.Addr().String()) { fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String()) } - // Parse and symbolize trace asynchronously while browser opens. - go parseEvents() - // Start http server. http.HandleFunc("/", httpMain) err = http.Serve(ln, nil) dief("failed to start http server: %v\n", err) } +var ranges []Range + var loader struct { once sync.Once events []*trace.Event @@ -118,13 +136,23 @@ func parseEvents() ([]*trace.Event, error) { // httpMain serves the starting page. func httpMain(w http.ResponseWriter, r *http.Request) { - w.Write(templMain) + if err := templMain.Execute(w, ranges); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } -var templMain = []byte(` +var templMain = template.Must(template.New("").Parse(` -View trace
+{{if $}} + {{range $e := $}} + View trace ({{$e.Name}})
+ {{end}} +
+{{else}} + View trace
+{{end}} Goroutine analysis
Network blocking profile
Synchronization blocking profile
@@ -132,7 +160,7 @@ var templMain = []byte(` Scheduler latency profile
-`) +`)) // startBrowser tries to open the URL in a browser // and reports whether it succeeds. diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go index 7782a5efc8dd33..2b6a37bfd8dbcb 100644 --- a/src/cmd/trace/trace.go +++ b/src/cmd/trace/trace.go @@ -14,6 +14,7 @@ import ( "runtime" "strconv" "strings" + "time" ) func init() { @@ -29,17 +30,11 @@ func httpTrace(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } - - params := "" - if goids := r.FormValue("goid"); goids != "" { - goid, err := strconv.ParseUint(goids, 10, 64) - if err != nil { - http.Error(w, fmt.Sprintf("failed to parse goid parameter '%v': %v", goids, err), http.StatusInternalServerError) - return - } - params = fmt.Sprintf("?goid=%v", goid) + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return } - html := strings.Replace(templTrace, "{{PARAMS}}", params, -1) + html := strings.Replace(templTrace, "{{PARAMS}}", r.Form.Encode(), -1) w.Write([]byte(html)) } @@ -118,7 +113,7 @@ var templTrace = ` viewer.globalMode = true; document.body.appendChild(viewer); - url = '/jsontrace{{PARAMS}}'; + url = '/jsontrace?{{PARAMS}}'; load(); }); }()); @@ -150,6 +145,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) { } if goids := r.FormValue("goid"); goids != "" { + // If goid argument is present, we are rendering a trace for this particular goroutine. goid, err := strconv.ParseUint(goids, 10, 64) if err != nil { log.Printf("failed to parse goid parameter '%v': %v", goids, err) @@ -164,13 +160,81 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) { params.gs = trace.RelatedGoroutines(events, goid) } - err = json.NewEncoder(w).Encode(generateTrace(params)) + data := generateTrace(params) + + if startStr, endStr := r.FormValue("start"), r.FormValue("end"); startStr != "" && endStr != "" { + // If start/end arguments are present, we are rendering a range of the trace. + start, err := strconv.ParseUint(startStr, 10, 64) + if err != nil { + log.Printf("failed to parse start parameter '%v': %v", startStr, err) + return + } + end, err := strconv.ParseUint(endStr, 10, 64) + if err != nil { + log.Printf("failed to parse end parameter '%v': %v", endStr, err) + return + } + if start >= uint64(len(data.Events)) || end <= start || end > uint64(len(data.Events)) { + log.Printf("bogus start/end parameters: %v/%v, trace size %v", start, end, len(data.Events)) + return + } + data.Events = append(data.Events[start:end], data.Events[data.footer:]...) + } + err = json.NewEncoder(w).Encode(data) if err != nil { log.Printf("failed to serialize trace: %v", err) return } } +type Range struct { + Name string + Start int + End int +} + +// splitTrace splits the trace into a number of ranges, +// each resulting in approx 100MB of json output (trace viewer can hardly handle more). +func splitTrace(data ViewerData) []Range { + const rangeSize = 100 << 20 + var ranges []Range + cw := new(countingWriter) + enc := json.NewEncoder(cw) + // First calculate size of the mandatory part of the trace. + // This includes stack traces and thread names. + data1 := data + data1.Events = data.Events[data.footer:] + enc.Encode(data1) + auxSize := cw.size + cw.size = 0 + // Then calculate size of each individual event and group them into ranges. + for i, start := 0, 0; i < data.footer; i++ { + enc.Encode(data.Events[i]) + if cw.size+auxSize > rangeSize || i == data.footer-1 { + ranges = append(ranges, Range{ + Name: fmt.Sprintf("%v-%v", time.Duration(data.Events[start].Time*1000), time.Duration(data.Events[i].Time*1000)), + Start: start, + End: i + 1, + }) + start = i + 1 + cw.size = 0 + } + } + if len(ranges) == 1 { + ranges = nil + } + return ranges +} + +type countingWriter struct { + size int +} + +func (cw *countingWriter) Write(data []byte) (int, error) { + cw.size += len(data) + return len(data), nil +} + type traceParams struct { events []*trace.Event gtrace bool @@ -204,6 +268,9 @@ type ViewerData struct { Events []*ViewerEvent `json:"traceEvents"` Frames map[string]ViewerFrame `json:"stackFrames"` TimeUnit string `json:"displayTimeUnit"` + + // This is where mandatory part of the trace starts (e.g. thread names) + footer int } type ViewerEvent struct { @@ -355,6 +422,7 @@ func generateTrace(params *traceParams) ViewerData { } } + ctx.data.footer = len(ctx.data.Events) ctx.emit(&ViewerEvent{Name: "process_name", Phase: "M", Pid: 0, Arg: &NameArg{"PROCS"}}) ctx.emit(&ViewerEvent{Name: "process_sort_index", Phase: "M", Pid: 0, Arg: &SortIndexArg{1}}) From 7af2ce3f159760033c903b3730bfb5995b4edd40 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 10 May 2016 21:28:30 -0700 Subject: [PATCH 087/267] cmd/build: reject non-existant directories in ImportDir Re-apply @adg's CL https://golang.org/cl/7129048 that was previously disabled in https://golang.org/cl/7235052 because it broke `godoc net/http` for go1.1. Currently `godoc net/http` seems to work fine with this CL. Fixes #3428. Change-Id: I7df06df02fd62dededac6ec60bea62561be59cf1 Reviewed-on: https://go-review.googlesource.com/23013 Run-TryBot: Andrew Gerrand TryBot-Result: Gobot Gobot Reviewed-by: Andrew Gerrand --- src/go/build/build.go | 6 +++++- src/go/build/build_test.go | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index fa258d3dc671a4..0818aa050178b9 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -403,7 +403,11 @@ func (p *Package) IsCommand() bool { // ImportDir is like Import but processes the Go package found in // the named directory. func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { - return ctxt.Import(".", dir, mode) + p, err := ctxt.Import(".", dir, mode) + if err == nil && !ctxt.isDir(p.Dir) { + err = fmt.Errorf("%q is not a directory", p.Dir) + } + return p, err } // NoGoError is the error used by Import to describe a directory diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index c9f906a7da6d0a..6bade1d318c6e7 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -5,6 +5,7 @@ package build import ( + "fmt" "internal/testenv" "io" "os" @@ -345,3 +346,13 @@ func TestImportVendorParentFailure(t *testing.T) { t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e) } } + +// Issue 3248 +func TestBogusDirectory(t *testing.T) { + const dir = "/foo/bar/baz/gopher" + _, err := ImportDir(dir, FindOnly) + want := fmt.Sprintf("%q is not a directory", filepath.FromSlash(dir)) + if err == nil || err.Error() != want { + t.Errorf("got error %q, want %q", err, want) + } +} From 8f48efb31c7cdddeec7d4221174254466b0891dd Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Fri, 13 May 2016 02:05:48 +0530 Subject: [PATCH 088/267] fmt: remove extra space in too few arguments example Change-Id: Iae4855c52c4da9755277251d22121226507ea26a Reviewed-on: https://go-review.googlesource.com/23074 Reviewed-by: Brad Fitzpatrick --- src/fmt/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index fefc10c19de8ad..c312914b44a48b 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -210,7 +210,7 @@ Too many arguments: %!(EXTRA type=value) Printf("hi", "guys"): hi%!(EXTRA string=guys) Too few arguments: %!verb(MISSING) - Printf("hi%d"): hi %!d(MISSING) + Printf("hi%d"): hi%!d(MISSING) Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC) Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi From eb69476c66339ca494f98e65a78d315da99a9c79 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 12 May 2016 13:55:46 -0700 Subject: [PATCH 089/267] text/template: detect pathologically recursive template invocations Return an error message instead of eating memory and eventually triggering a stack overflow. Fixes #15618 Change-Id: I3dcf1d669104690a17847a20fbfeb6d7e39e8751 Reviewed-on: https://go-review.googlesource.com/23091 Reviewed-by: Rob Pike --- src/text/template/exec.go | 19 +++++++++++++++---- src/text/template/exec_test.go | 13 +++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 22881c685279f6..8e5ad93ca6b5b8 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -15,14 +15,21 @@ import ( "text/template/parse" ) +// maxExecDepth specifies the maximum stack depth of templates within +// templates. This limit is only practically reached by accidentally +// recursive template invocations. This limit allows us to return +// an error instead of triggering a stack overflow. +const maxExecDepth = 100000 + // state represents the state of an execution. It's not part of the // template so that multiple executions of the same template // can execute in parallel. type state struct { - tmpl *Template - wr io.Writer - node parse.Node // current node, for errors - vars []variable // push-down stack of variable values. + tmpl *Template + wr io.Writer + node parse.Node // current node, for errors + vars []variable // push-down stack of variable values. + depth int // the height of the stack of executing templates. } // variable holds the dynamic value of a variable such as $, $x etc. @@ -363,9 +370,13 @@ func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { if tmpl == nil { s.errorf("template %q not defined", t.Name) } + if s.depth == maxExecDepth { + s.errorf("exceeded maximum template depth (%v)", maxExecDepth) + } // Variables declared by the pipeline persist. dot = s.evalPipeline(dot, t.Pipe) newState := *s + newState.depth++ newState.tmpl = tmpl // No dynamic scoping: template invocations inherit no variables. newState.vars = []variable{{"$", dot}} diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index bc2aa683ec9a06..3ef065edcfdebe 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -1297,3 +1297,16 @@ func TestMissingFieldOnNil(t *testing.T) { t.Errorf("got error %q, want %q", got, want) } } + +func TestMaxExecDepth(t *testing.T) { + tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`)) + err := tmpl.Execute(ioutil.Discard, nil) + got := "" + if err != nil { + got = err.Error() + } + const want = "exceeded maximum template depth" + if !strings.Contains(got, want) { + t.Errorf("got error %q; want %q", got, want) + } +} From 4cffe44e361deb39e3274774a7984ab78a5b3931 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 12 May 2016 15:04:05 +1000 Subject: [PATCH 090/267] syscall: separate stdlib imports from others in mksyscall_windows.go Change-Id: I6610b872578d161e535565258039d9f064f01456 Reviewed-on: https://go-review.googlesource.com/23070 Reviewed-by: Nigel Tao Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot --- src/syscall/mksyscall_windows.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index 84747962ab559e..1e0d9401e746f4 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -597,14 +597,20 @@ func (f *Fn) HelperName() string { // Source files and functions. type Source struct { - Funcs []*Fn - Files []string - Imports []string + Funcs []*Fn + Files []string + StdLibImports []string + ExternalImports []string } func (src *Source) Import(pkg string) { - src.Imports = append(src.Imports, pkg) - sort.Strings(src.Imports) + src.StdLibImports = append(src.StdLibImports, pkg) + sort.Strings(src.StdLibImports) +} + +func (src *Source) ExternalImport(pkg string) { + src.ExternalImports = append(src.ExternalImports, pkg) + sort.Strings(src.ExternalImports) } // ParseFiles parses files listed in fs and extracts all syscall @@ -614,9 +620,10 @@ func ParseFiles(fs []string) (*Source, error) { src := &Source{ Funcs: make([]*Fn, 0), Files: make([]string, 0), - Imports: []string{ + StdLibImports: []string{ "unsafe", }, + ExternalImports: make([]string, 0), } for _, file := range fs { if err := src.ParseFile(file); err != nil { @@ -731,7 +738,7 @@ func (src *Source) Generate(w io.Writer) error { src.Import("internal/syscall/windows/sysdll") case pkgXSysWindows: default: - src.Import("golang.org/x/sys/windows") + src.ExternalImport("golang.org/x/sys/windows") } } if packageName != "syscall" { @@ -809,7 +816,10 @@ const srcTemplate = ` package {{packagename}} import ( -{{range .Imports}}"{{.}}" +{{range .StdLibImports}}"{{.}}" +{{end}} + +{{range .ExternalImports}}"{{.}}" {{end}} ) From 15f2d0e45227f68024f3415d9466055877b70426 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 12 May 2016 22:12:11 +0000 Subject: [PATCH 091/267] net, net/http: don't trace UDP dials The httptrace.ConnectStart and ConnectDone hooks are just about the post-DNS connection to the host. We were accidentally also firing on the UDP dials to DNS. Exclude those for now. We can add them back later as separate hooks if desired. (but they'd only work for pure Go DNS) This wasn't noticed earlier because I was developing on a Mac at the time, which always uses cgo for DNS. When running other tests on Linux, I started seeing UDP dials. Updates #12580 Change-Id: I2b2403f2483e227308fe008019f1100f6300250b Reviewed-on: https://go-review.googlesource.com/23069 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/internal/nettrace/nettrace.go | 12 +++++++----- src/net/dial.go | 12 +++++++++++- src/net/http/transport_test.go | 4 ++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/internal/nettrace/nettrace.go b/src/internal/nettrace/nettrace.go index 51a8b2cc5ae645..0f85d727c605bd 100644 --- a/src/internal/nettrace/nettrace.go +++ b/src/internal/nettrace/nettrace.go @@ -32,12 +32,14 @@ type Trace struct { // actually be for circular dependency reasons. DNSDone func(netIPs []interface{}, coalesced bool, err error) - // ConnectStart is called before a Dial. In the case of - // DualStack (Happy Eyeballs) dialing, this may be called - // multiple times, from multiple goroutines. + // ConnectStart is called before a TCPAddr or UnixAddr + // Dial. In the case of DualStack (Happy Eyeballs) dialing, + // this may be called multiple times, from multiple + // goroutines. ConnectStart func(network, addr string) - // ConnectStart is called after a Dial with the results. It - // may also be called multiple times, like ConnectStart. + // ConnectStart is called after a TCPAddr or UnixAddr Dial + // with the results. It may also be called multiple times, + // like ConnectStart. ConnectDone func(network, addr string, err error) } diff --git a/src/net/dial.go b/src/net/dial.go index 256ef3806147c4..5985421b0661a9 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -472,11 +472,21 @@ func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (Conn, error) return nil, firstErr } +// traceDialType reports whether ra is an address type for which +// nettrace.Trace should trace. +func traceDialType(ra Addr) bool { + switch ra.(type) { + case *TCPAddr, *UnixAddr: + return true + } + return false +} + // dialSingle attempts to establish and returns a single connection to // the destination address. func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) { trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) - if trace != nil { + if trace != nil && traceDialType(ra) { raStr := ra.String() if trace.ConnectStart != nil { trace.ConnectStart(dp.network, raStr) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index bde052524cb8da..ab26de2e9526a4 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3292,6 +3292,7 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { wantSub("Getting conn for dns-is-faked.golang:" + port) wantSub("DNS start: {Host:dns-is-faked.golang}") wantSub("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err: Coalesced:false}") + wantSub("Connecting to tcp " + ts.Listener.Addr().String()) wantSub("connected to tcp " + ts.Listener.Addr().String() + " = ") wantSub("Reused:false WasIdle:false IdleTime:0s") wantSub("first response byte") @@ -3299,6 +3300,9 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { wantSub("WroteRequest: {Err:}") wantSub("Wait100Continue") wantSub("Got100Continue") + if strings.Contains(got, " to udp ") { + t.Errorf("should not see UDP (DNS) connections") + } if t.Failed() { t.Errorf("Output:\n%s", got) } From be5782c330f2c743f81942f5bc1b9c1e04296d44 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 13 May 2016 09:25:25 +0200 Subject: [PATCH 092/267] doc/go1.7.txt: add cmd/trace changes Change-Id: Iaf455d1a2863ff752e0c398e1c364373b4d36614 Reviewed-on: https://go-review.googlesource.com/23084 Reviewed-by: Dmitry Vyukov --- doc/go1.7.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/go1.7.txt b/doc/go1.7.txt index adac6a367a83fd..d50f1f1032ec96 100644 --- a/doc/go1.7.txt +++ b/doc/go1.7.txt @@ -7,6 +7,9 @@ cmd/compile: smaller binaries (many CLs) cmd/go, go/build: add support for Fortran (CL 19670, CL 4114) cmd/doc: group constructors with types (CL 22354) cmd/go, go/build: binary-only package support (CL 22433) +cmd/trace: file:line is embed into traces (CL 21732) which makes binary argument optional (CL 22410) +cmd/trace: now supports visualization of very large traces by splitting them into parts (CL 22731) +cmd/trace: tracing has become significantly faster (CL 21512) Ports: From 2cc0f2209653f9f6931e0c3a1fb63e581a0fe87f Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 13 May 2016 11:10:29 +0900 Subject: [PATCH 093/267] Revert "cmd/build: reject non-existant directories in ImportDir" This reverts commit 7af2ce3f159760033c903b3730bfb5995b4edd40. The commit had a wrong prefix in the description line, probably misreconginized something. As a result it broke golang.org/x/tools/godoc and golang.org/x/tools/cmd/godoc like the following: --- FAIL: TestCLI (10.90s) --- FAIL: TestWeb (13.74s) FAIL FAIL golang.org/x/tools/cmd/godoc 36.428s --- FAIL: TestCommandLine (0.00s) FAIL FAIL golang.org/x/tools/godoc 0.068s Change-Id: I362a862a4ded8592dec7488a28e7a256adee148f Reviewed-on: https://go-review.googlesource.com/23076 Run-TryBot: Mikio Hara Reviewed-by: Andrew Gerrand --- src/go/build/build.go | 6 +----- src/go/build/build_test.go | 11 ----------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index 0818aa050178b9..fa258d3dc671a4 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -403,11 +403,7 @@ func (p *Package) IsCommand() bool { // ImportDir is like Import but processes the Go package found in // the named directory. func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { - p, err := ctxt.Import(".", dir, mode) - if err == nil && !ctxt.isDir(p.Dir) { - err = fmt.Errorf("%q is not a directory", p.Dir) - } - return p, err + return ctxt.Import(".", dir, mode) } // NoGoError is the error used by Import to describe a directory diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 6bade1d318c6e7..c9f906a7da6d0a 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -5,7 +5,6 @@ package build import ( - "fmt" "internal/testenv" "io" "os" @@ -346,13 +345,3 @@ func TestImportVendorParentFailure(t *testing.T) { t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e) } } - -// Issue 3248 -func TestBogusDirectory(t *testing.T) { - const dir = "/foo/bar/baz/gopher" - _, err := ImportDir(dir, FindOnly) - want := fmt.Sprintf("%q is not a directory", filepath.FromSlash(dir)) - if err == nil || err.Error() != want { - t.Errorf("got error %q, want %q", err, want) - } -} From 0cc710dca63b79ed2dd6ce9375502e76e5fc0484 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Fri, 13 May 2016 12:33:27 -0400 Subject: [PATCH 094/267] reflect: fix method type string By picking up a spurious tFlagExtraStar, the method type was printing as unc instead of func. Updates #15673 Change-Id: I0c2c189b99bdd4caeb393693be7520b8e3f342bf Reviewed-on: https://go-review.googlesource.com/23103 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/reflect/all_test.go | 21 +++++++++++++++++++++ src/reflect/type.go | 1 + 2 files changed, 22 insertions(+) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 5beec63273b526..9799fee3573557 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -5782,3 +5782,24 @@ func TestMethodPkgPathReadable(t *testing.T) { t.Errorf(`PkgPath=%q, want "reflect"`, m.PkgPath) } } + +func TestTypeStrings(t *testing.T) { + type stringTest struct { + typ Type + want string + } + stringTests := []stringTest{ + {TypeOf(func(int) {}), "func(int)"}, + {FuncOf([]Type{TypeOf(int(0))}, nil, false), "func(int)"}, + {TypeOf(XM{}), "reflect_test.XM"}, + {TypeOf(new(XM)), "*reflect_test.XM"}, + {TypeOf(new(XM).String), "func() string"}, + {TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"}, + } + + for i, test := range stringTests { + if got, want := test.typ.String(), test.want; got != want { + t.Errorf("type %d String()=%q, want %q", i, got, want) + } + } +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 5c6e3d55009d7e..3bfff4a7cc6aa0 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1985,6 +1985,7 @@ func FuncOf(in, out []Type, variadic bool) Type { if len(args) > 50 { panic("reflect.FuncOf does not support more than 50 arguments") } + ft.tflag = 0 ft.hash = hash ft.inCount = uint16(len(in)) ft.outCount = uint16(len(out)) From 19619c21c36d1695000f5b798241971dfdb2cc2d Mon Sep 17 00:00:00 2001 From: Tom Bergan Date: Thu, 12 May 2016 22:03:46 -0700 Subject: [PATCH 095/267] net, net/http: don't trace DNS dials This fixes change https://go-review.googlesource.com/#/c/23069/, which assumes all DNS requests are UDP. This is not true -- DNS requests can be TCP in some cases. See: https://tip.golang.org/src/net/dnsclient_unix.go#L154 https://en.wikipedia.org/wiki/Domain_Name_System#Protocol_transport Also, the test code added by the above change doesn't actually test anything because the test uses a faked DNS resolver that doesn't actually make any DNS queries. I fixed that by adding another test that uses the system DNS resolver. Updates #12580 Change-Id: I6c24c03ebab84d437d3ac610fd6eb5353753c490 Reviewed-on: https://go-review.googlesource.com/23101 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/internal/nettrace/nettrace.go | 12 ++++---- src/net/dial.go | 23 ++++++++-------- src/net/http/transport_test.go | 46 +++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/internal/nettrace/nettrace.go b/src/internal/nettrace/nettrace.go index 0f85d727c605bd..de3254df589f0e 100644 --- a/src/internal/nettrace/nettrace.go +++ b/src/internal/nettrace/nettrace.go @@ -32,14 +32,14 @@ type Trace struct { // actually be for circular dependency reasons. DNSDone func(netIPs []interface{}, coalesced bool, err error) - // ConnectStart is called before a TCPAddr or UnixAddr - // Dial. In the case of DualStack (Happy Eyeballs) dialing, - // this may be called multiple times, from multiple + // ConnectStart is called before a Dial, excluding Dials made + // during DNS lookups. In the case of DualStack (Happy Eyeballs) + // dialing, this may be called multiple times, from multiple // goroutines. ConnectStart func(network, addr string) - // ConnectStart is called after a TCPAddr or UnixAddr Dial - // with the results. It may also be called multiple times, - // like ConnectStart. + // ConnectStart is called after a Dial with the results, excluding + // Dials made during DNS lookups. It may also be called multiple + // times, like ConnectStart. ConnectDone func(network, addr string, err error) } diff --git a/src/net/dial.go b/src/net/dial.go index 5985421b0661a9..16f67a2f337427 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -317,7 +317,16 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn ctx = subCtx } - addrs, err := resolveAddrList(ctx, "dial", network, address, d.LocalAddr) + // Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups. + resolveCtx := ctx + if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil { + shadow := *trace + shadow.ConnectStart = nil + shadow.ConnectDone = nil + resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow) + } + + addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr) if err != nil { return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err} } @@ -472,21 +481,11 @@ func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (Conn, error) return nil, firstErr } -// traceDialType reports whether ra is an address type for which -// nettrace.Trace should trace. -func traceDialType(ra Addr) bool { - switch ra.(type) { - case *TCPAddr, *UnixAddr: - return true - } - return false -} - // dialSingle attempts to establish and returns a single connection to // the destination address. func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) { trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) - if trace != nil && traceDialType(ra) { + if trace != nil { raStr := ra.String() if trace.ConnectStart != nil { trace.ConnectStart(dp.network, raStr) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index ab26de2e9526a4..328fd5727b9e6b 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3308,6 +3308,52 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { } } +func TestTransportEventTraceRealDNS(t *testing.T) { + defer afterTest(t) + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + var mu sync.Mutex + var buf bytes.Buffer + logf := func(format string, args ...interface{}) { + mu.Lock() + defer mu.Unlock() + fmt.Fprintf(&buf, format, args...) + buf.WriteByte('\n') + } + + req, _ := NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil) + trace := &httptrace.ClientTrace{ + DNSStart: func(e httptrace.DNSStartInfo) { logf("DNSStart: %+v", e) }, + DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNSDone: %+v", e) }, + ConnectStart: func(network, addr string) { logf("ConnectStart: %s %s", network, addr) }, + ConnectDone: func(network, addr string, err error) { logf("ConnectDone: %s %s %v", network, addr, err) }, + } + req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace)) + + resp, err := c.Do(req) + if err == nil { + resp.Body.Close() + t.Fatal("expected error during DNS lookup") + } + + got := buf.String() + wantSub := func(sub string) { + if !strings.Contains(got, sub) { + t.Errorf("expected substring %q in output.", sub) + } + } + wantSub("DNSStart: {Host:dns-should-not-resolve.golang}") + wantSub("DNSDone: {Addrs:[] Err:") + if strings.Contains(got, "ConnectStart") || strings.Contains(got, "ConnectDone") { + t.Errorf("should not see Connect events") + } + if t.Failed() { + t.Errorf("Output:\n%s", got) + } +} + func TestTransportMaxIdleConns(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { From 041cc148faae23714c38ec9e4388715d99aef518 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 13 May 2016 05:02:00 +0900 Subject: [PATCH 096/267] net: deflake TestPointToPointInterface and TestInterfaceArrivalAndDeparture Fixes #6879. Change-Id: I9ed2460cf14cb9322d9521e7af910efa48abdaf0 Reviewed-on: https://go-review.googlesource.com/23112 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/net/interface_bsd_test.go | 9 +++++++-- src/net/interface_unix_test.go | 17 +++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/net/interface_bsd_test.go b/src/net/interface_bsd_test.go index ed1af554ad4294..69b0fbcab3de30 100644 --- a/src/net/interface_bsd_test.go +++ b/src/net/interface_bsd_test.go @@ -9,10 +9,15 @@ package net import ( "fmt" "os/exec" + "runtime" ) -func (ti *testInterface) setBroadcast(suffix int) error { - ti.name = fmt.Sprintf("vlan%d", suffix) +func (ti *testInterface) setBroadcast(vid int) error { + if runtime.GOOS == "openbsd" { + ti.name = fmt.Sprintf("vether%d", vid) + } else { + ti.name = fmt.Sprintf("vlan%d", vid) + } xname, err := exec.LookPath("ifconfig") if err != nil { return err diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go index 2ebf0897360be9..36510ebf080fbf 100644 --- a/src/net/interface_unix_test.go +++ b/src/net/interface_unix_test.go @@ -7,6 +7,7 @@ package net import ( + "fmt" "os" "os/exec" "runtime" @@ -24,8 +25,8 @@ type testInterface struct { func (ti *testInterface) setup() error { for _, cmd := range ti.setupCmds { - if err := cmd.Run(); err != nil { - return err + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err) } } return nil @@ -33,8 +34,8 @@ func (ti *testInterface) setup() error { func (ti *testInterface) teardown() error { for _, cmd := range ti.teardownCmds { - if err := cmd.Run(); err != nil { - return err + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err) } } return nil @@ -51,6 +52,8 @@ func TestPointToPointInterface(t *testing.T) { t.Skip("must be root") } + // We suppose that using IPv4 link-local addresses doesn't + // harm anyone. local, remote := "169.254.0.1", "169.254.0.254" ip := ParseIP(remote) for i := 0; i < 3; i++ { @@ -100,15 +103,17 @@ func TestInterfaceArrivalAndDeparture(t *testing.T) { t.Skip("must be root") } + // We suppose that using IPv4 link-local addresses and the + // dot1Q ID for Token Ring and FDDI doesn't harm anyone. local, remote := "169.254.0.1", "169.254.0.254" ip := ParseIP(remote) - for i := 0; i < 3; i++ { + for _, vid := range []int{1002, 1003, 1004, 1005} { ift1, err := Interfaces() if err != nil { t.Fatal(err) } ti := &testInterface{local: local, remote: remote} - if err := ti.setBroadcast(5682 + i); err != nil { + if err := ti.setBroadcast(vid); err != nil { t.Skipf("test requires external command: %v", err) } if err := ti.setup(); err != nil { From d8b08c3aa49d9aaac6ff34dbb8516040cc88a13a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 11 May 2016 14:57:33 -0400 Subject: [PATCH 097/267] runtime: perform publication barrier even for noscan objects Currently we only execute a publication barrier for scan objects (and skip it for noscan objects). This used to be okay because GC would never consult the object itself (so it wouldn't observe uninitialized memory even if it found a pointer to a noscan object), and the heap bitmap was pre-initialized to noscan. However, now we explicitly initialize the heap bitmap for noscan objects when we allocate them. While the GC will still never consult the contents of a noscan object, it does need to see the initialized heap bitmap. Hence, we need to execute a publication barrier to make the bitmap visible before user code can expose a pointer to the newly allocated object even for noscan objects. Change-Id: Ie4133c638db0d9055b4f7a8061a634d970627153 Reviewed-on: https://go-review.googlesource.com/23043 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/malloc.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index ae81b8681b90d1..b079a07d518456 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -699,16 +699,16 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { scanSize = typ.ptrdata } c.local_scan += scanSize - - // Ensure that the stores above that initialize x to - // type-safe memory and set the heap bits occur before - // the caller can make x observable to the garbage - // collector. Otherwise, on weakly ordered machines, - // the garbage collector could follow a pointer to x, - // but see uninitialized memory or stale heap bits. - publicationBarrier() } + // Ensure that the stores above that initialize x to + // type-safe memory and set the heap bits occur before + // the caller can make x observable to the garbage + // collector. Otherwise, on weakly ordered machines, + // the garbage collector could follow a pointer to x, + // but see uninitialized memory or stale heap bits. + publicationBarrier() + // Allocate black during GC. // All slots hold nil so no scanning is needed. // This may be racing with GC so do it atomically if there can be From 6181db53dbfec513300a236debbdc01735f00c07 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 May 2016 18:10:03 -0400 Subject: [PATCH 098/267] runtime: improve heapBitsSetType documentation Currently the heapBitsSetType documentation says that there are no races on the heap bitmap, but that isn't exactly true. There are no *write-write* races, but there are read-write races. Expand the documentation to explain this and why it's okay. Change-Id: Ibd92b69bcd6524a40a9dd4ec82422b50831071ed Reviewed-on: https://go-review.googlesource.com/23092 Reviewed-by: Rick Hudson --- src/runtime/mbitmap.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 27f8e66d50ce1c..ccefbcd8d62df2 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -847,10 +847,20 @@ func (s *mspan) countFree() int { // malloc does not call heapBitsSetType when there are no pointers, // because all free objects are marked as noscan during // heapBitsSweepSpan. +// // There can only be one allocation from a given span active at a time, -// so this code is not racing with other instances of itself, and -// the bitmap for a span always falls on byte boundaries. -// Hence, it can access the bitmap with racing. +// and the bitmap for a span always falls on byte boundaries, +// so there are no write-write races for access to the heap bitmap. +// Hence, heapBitsSetType can access the bitmap without atomics. +// +// There can be read-write races between heapBitsSetType and things +// that read the heap bitmap like scanobject. However, since +// heapBitsSetType is only used for objects that have not yet been +// made reachable, readers will ignore bits being modified by this +// function. This does mean this function cannot transiently modify +// bits that belong to neighboring objects. Also, on weakly-ordered +// machines, callers must execute a store/store (publication) barrier +// between calling this function and making the object reachable. // // TODO: This still has atomic accesses left over from when it could // race with GC accessing mark bits in the bitmap. Remove these. From 094afe0cf1aa4182d62a3aea6970933b7ae4a27d Mon Sep 17 00:00:00 2001 From: Konstantin Shaposhnikov Date: Sat, 14 May 2016 10:27:31 +0800 Subject: [PATCH 099/267] cmd/vendor: move cmd/internal/unvendor packages to cmd/vendor Updates #14047 Change-Id: I4b150533393bfb90e840497095ac32bcca4f04c2 Reviewed-on: https://go-review.googlesource.com/23114 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- misc/nacl/testzip.proto | 24 +++++++++---------- src/cmd/internal/objfile/disasm.go | 4 ++-- .../golang.org/x/arch/arm/armasm/Makefile | 0 .../golang.org/x/arch/arm/armasm/decode.go | 0 .../x/arch/arm/armasm/decode_test.go | 0 .../golang.org/x/arch/arm/armasm/ext_test.go | 0 .../golang.org/x/arch/arm/armasm/gnu.go | 0 .../golang.org/x/arch/arm/armasm/inst.go | 0 .../x/arch/arm/armasm/objdump_test.go | 0 .../x/arch/arm/armasm/objdumpext_test.go | 0 .../golang.org/x/arch/arm/armasm/plan9x.go | 0 .../golang.org/x/arch/arm/armasm/tables.go | 0 .../x/arch/arm/armasm/testdata/Makefile | 0 .../x/arch/arm/armasm/testdata/decode.txt | 0 .../golang.org/x/arch/x86/x86asm/Makefile | 0 .../golang.org/x/arch/x86/x86asm/decode.go | 0 .../x/arch/x86/x86asm/decode_test.go | 0 .../golang.org/x/arch/x86/x86asm/ext_test.go | 0 .../golang.org/x/arch/x86/x86asm/gnu.go | 0 .../golang.org/x/arch/x86/x86asm/inst.go | 0 .../golang.org/x/arch/x86/x86asm/inst_test.go | 0 .../golang.org/x/arch/x86/x86asm/intel.go | 0 .../x/arch/x86/x86asm/objdump_test.go | 0 .../x/arch/x86/x86asm/objdumpext_test.go | 0 .../x/arch/x86/x86asm/plan9ext_test.go | 0 .../golang.org/x/arch/x86/x86asm/plan9x.go | 0 .../x/arch/x86/x86asm/plan9x_test.go | 0 .../golang.org/x/arch/x86/x86asm/tables.go | 0 .../x/arch/x86/x86asm/testdata/Makefile | 0 .../x/arch/x86/x86asm/testdata/decode.txt | 0 .../x/arch/x86/x86asm/testdata/libmach8db.c | 0 .../golang.org/x/arch/x86/x86asm/xed_test.go | 0 .../x/arch/x86/x86asm/xedext_test.go | 0 .../{internal/unvendor => vendor}/vendor.json | 0 34 files changed, 14 insertions(+), 14 deletions(-) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/Makefile (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/decode.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/decode_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/ext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/gnu.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/inst.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/objdump_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/objdumpext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/plan9x.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/tables.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/testdata/Makefile (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/arm/armasm/testdata/decode.txt (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/Makefile (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/decode.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/decode_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/ext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/gnu.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/inst.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/inst_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/intel.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/objdump_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/objdumpext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/plan9ext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/plan9x.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/plan9x_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/tables.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/testdata/Makefile (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/testdata/decode.txt (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/xed_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/golang.org/x/arch/x86/x86asm/xedext_test.go (100%) rename src/cmd/{internal/unvendor => vendor}/vendor.json (100%) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index 8c14b87f0a5299..8a8784c8be011c 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -27,23 +27,23 @@ go src=.. internal objfile objfile.go - unvendor - golang.org - x - arch - arm - armasm - testdata - + - x86 - x86asm - testdata - + gofmt gofmt.go gofmt_test.go testdata + + vendor + golang.org + x + arch + arm + armasm + testdata + + + x86 + x86asm + testdata + + archive tar testdata diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go index d63f8f616f189e..25c3301ab88805 100644 --- a/src/cmd/internal/objfile/disasm.go +++ b/src/cmd/internal/objfile/disasm.go @@ -15,8 +15,8 @@ import ( "strings" "text/tabwriter" - "cmd/internal/unvendor/golang.org/x/arch/arm/armasm" - "cmd/internal/unvendor/golang.org/x/arch/x86/x86asm" + "golang.org/x/arch/arm/armasm" + "golang.org/x/arch/x86/x86asm" ) // Disasm is a disassembler for a given File. diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile b/src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile b/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt b/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go similarity index 100% rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go diff --git a/src/cmd/internal/unvendor/vendor.json b/src/cmd/vendor/vendor.json similarity index 100% rename from src/cmd/internal/unvendor/vendor.json rename to src/cmd/vendor/vendor.json From 5f833121cb8e7722667d17dcf07bb32e4e524f23 Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Sat, 14 May 2016 10:23:09 -0700 Subject: [PATCH 100/267] archive/zip: use HTTPS for documentation link The resource is available over (and redirects to) HTTPS, it seems like a good idea to save a redirect and ensure an encrypted connection. Change-Id: I262c7616ae289cdd756b6f67573ba6bd7e3e0ca6 Reviewed-on: https://go-review.googlesource.com/23104 Reviewed-by: Brad Fitzpatrick --- src/archive/zip/struct.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go index 5ee4f88f8036ba..e92d02f8a2e872 100644 --- a/src/archive/zip/struct.go +++ b/src/archive/zip/struct.go @@ -5,7 +5,7 @@ /* Package zip provides support for reading and writing ZIP archives. -See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT +See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT This package does not support disk spanning. From 2699da180967e5d5dab2cc64deeca4680bf2b2fb Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 13 May 2016 14:26:30 +1000 Subject: [PATCH 101/267] time: set Local.name on windows Local.String() returns "Local" on every OS, but windows. Change windows code to do like others. Updates #15568 Change-Id: I7a4d2713d940e2a01cff9d7f5cefc89def07546a Reviewed-on: https://go-review.googlesource.com/23078 Reviewed-by: Brad Fitzpatrick --- src/time/zoneinfo_test.go | 9 +++++++++ src/time/zoneinfo_windows.go | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index 0b7584ab9c2ffd..4b50dc509002f0 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -61,3 +61,12 @@ func TestFirstZone(t *testing.T) { } } } + +func TestLocationNames(t *testing.T) { + if time.Local.String() != "Local" { + t.Errorf(`invalid Local location name: got %q want "Local"`, time.Local) + } + if time.UTC.String() != "UTC" { + t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC) + } +} diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go index c753119d5db765..a6546f54b86ac7 100644 --- a/src/time/zoneinfo_windows.go +++ b/src/time/zoneinfo_windows.go @@ -140,6 +140,8 @@ func pseudoUnix(year int, d *syscall.Systemtime) int64 { func initLocalFromTZI(i *syscall.Timezoneinformation) { l := &localLoc + l.name = "Local" + nzone := 1 if i.StandardDate.Month > 0 { nzone++ From aba7b3e91cea1c95a1803357bcf219b0591d3c12 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 23 Apr 2016 22:36:41 +0900 Subject: [PATCH 102/267] vendor: import golang.org/x/net/route golang.org/x/net/route becomes vendor/golang.org/x/net/route. At git rev 30be488 (golang.org/cl/22446) Updates #14724. Change-Id: I41cfb5443aeecac4c71e843c09eb8c1d4b7413ea Reviewed-on: https://go-review.googlesource.com/22450 Reviewed-by: Brad Fitzpatrick --- src/vendor/golang.org/x/net/route/address.go | 269 ++++++++++++ .../x/net/route/address_darwin_test.go | 63 +++ .../golang.org/x/net/route/address_test.go | 103 +++++ src/vendor/golang.org/x/net/route/binary.go | 90 ++++ .../golang.org/x/net/route/defs_darwin.go | 106 +++++ .../golang.org/x/net/route/defs_dragonfly.go | 105 +++++ .../golang.org/x/net/route/defs_freebsd.go | 329 +++++++++++++++ .../golang.org/x/net/route/defs_netbsd.go | 104 +++++ .../golang.org/x/net/route/defs_openbsd.go | 93 +++++ .../golang.org/x/net/route/interface.go | 64 +++ .../x/net/route/interface_announce.go | 32 ++ .../x/net/route/interface_classic.go | 66 +++ .../x/net/route/interface_freebsd.go | 78 ++++ .../x/net/route/interface_multicast.go | 30 ++ .../x/net/route/interface_openbsd.go | 83 ++++ src/vendor/golang.org/x/net/route/message.go | 70 ++++ .../x/net/route/message_darwin_test.go | 27 ++ .../x/net/route/message_freebsd_test.go | 106 +++++ .../golang.org/x/net/route/message_test.go | 95 +++++ src/vendor/golang.org/x/net/route/route.go | 74 ++++ .../golang.org/x/net/route/route_classic.go | 31 ++ .../golang.org/x/net/route/route_openbsd.go | 28 ++ .../golang.org/x/net/route/route_test.go | 385 ++++++++++++++++++ src/vendor/golang.org/x/net/route/sys.go | 40 ++ .../golang.org/x/net/route/sys_darwin.go | 80 ++++ .../golang.org/x/net/route/sys_dragonfly.go | 71 ++++ .../golang.org/x/net/route/sys_freebsd.go | 150 +++++++ .../golang.org/x/net/route/sys_netbsd.go | 67 +++ .../golang.org/x/net/route/sys_openbsd.go | 72 ++++ src/vendor/golang.org/x/net/route/syscall.go | 33 ++ src/vendor/golang.org/x/net/route/syscall.s | 8 + .../golang.org/x/net/route/zsys_darwin.go | 93 +++++ .../golang.org/x/net/route/zsys_dragonfly.go | 92 +++++ .../x/net/route/zsys_freebsd_386.go | 120 ++++++ .../x/net/route/zsys_freebsd_amd64.go | 117 ++++++ .../x/net/route/zsys_freebsd_arm.go | 117 ++++++ .../golang.org/x/net/route/zsys_netbsd.go | 91 +++++ .../golang.org/x/net/route/zsys_openbsd.go | 80 ++++ 38 files changed, 3662 insertions(+) create mode 100644 src/vendor/golang.org/x/net/route/address.go create mode 100644 src/vendor/golang.org/x/net/route/address_darwin_test.go create mode 100644 src/vendor/golang.org/x/net/route/address_test.go create mode 100644 src/vendor/golang.org/x/net/route/binary.go create mode 100644 src/vendor/golang.org/x/net/route/defs_darwin.go create mode 100644 src/vendor/golang.org/x/net/route/defs_dragonfly.go create mode 100644 src/vendor/golang.org/x/net/route/defs_freebsd.go create mode 100644 src/vendor/golang.org/x/net/route/defs_netbsd.go create mode 100644 src/vendor/golang.org/x/net/route/defs_openbsd.go create mode 100644 src/vendor/golang.org/x/net/route/interface.go create mode 100644 src/vendor/golang.org/x/net/route/interface_announce.go create mode 100644 src/vendor/golang.org/x/net/route/interface_classic.go create mode 100644 src/vendor/golang.org/x/net/route/interface_freebsd.go create mode 100644 src/vendor/golang.org/x/net/route/interface_multicast.go create mode 100644 src/vendor/golang.org/x/net/route/interface_openbsd.go create mode 100644 src/vendor/golang.org/x/net/route/message.go create mode 100644 src/vendor/golang.org/x/net/route/message_darwin_test.go create mode 100644 src/vendor/golang.org/x/net/route/message_freebsd_test.go create mode 100644 src/vendor/golang.org/x/net/route/message_test.go create mode 100644 src/vendor/golang.org/x/net/route/route.go create mode 100644 src/vendor/golang.org/x/net/route/route_classic.go create mode 100644 src/vendor/golang.org/x/net/route/route_openbsd.go create mode 100644 src/vendor/golang.org/x/net/route/route_test.go create mode 100644 src/vendor/golang.org/x/net/route/sys.go create mode 100644 src/vendor/golang.org/x/net/route/sys_darwin.go create mode 100644 src/vendor/golang.org/x/net/route/sys_dragonfly.go create mode 100644 src/vendor/golang.org/x/net/route/sys_freebsd.go create mode 100644 src/vendor/golang.org/x/net/route/sys_netbsd.go create mode 100644 src/vendor/golang.org/x/net/route/sys_openbsd.go create mode 100644 src/vendor/golang.org/x/net/route/syscall.go create mode 100644 src/vendor/golang.org/x/net/route/syscall.s create mode 100644 src/vendor/golang.org/x/net/route/zsys_darwin.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_dragonfly.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_freebsd_386.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_netbsd.go create mode 100644 src/vendor/golang.org/x/net/route/zsys_openbsd.go diff --git a/src/vendor/golang.org/x/net/route/address.go b/src/vendor/golang.org/x/net/route/address.go new file mode 100644 index 00000000000000..206a8371d43565 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/address.go @@ -0,0 +1,269 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +import "runtime" + +// An Addr represents an address associated with packet routing. +type Addr interface { + // Family returns an address family. + Family() int +} + +// A LinkAddr represents a link-layer address. +type LinkAddr struct { + Index int // interface index when attached + Name string // interface name when attached + Addr []byte // link-layer address when attached +} + +// Family implements the Family method of Addr interface. +func (a *LinkAddr) Family() int { return sysAF_LINK } + +func parseLinkAddr(b []byte) (Addr, error) { + if len(b) < 8 { + return nil, errInvalidAddr + } + _, a, err := parseKernelLinkAddr(sysAF_LINK, b[4:]) + if err != nil { + return nil, err + } + a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4])) + return a, nil +} + +// parseKernelLinkAddr parses b as a link-layer address in +// conventional BSD kernel form. +func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) { + // The encoding looks like the following: + // +----------------------------+ + // | Type (1 octet) | + // +----------------------------+ + // | Name length (1 octet) | + // +----------------------------+ + // | Address length (1 octet) | + // +----------------------------+ + // | Selector length (1 octet) | + // +----------------------------+ + // | Data (variable) | + // +----------------------------+ + // + // On some platforms, all-bit-one of length field means "don't + // care". + nlen, alen, slen := int(b[1]), int(b[2]), int(b[3]) + if nlen == 0xff { + nlen = 0 + } + if alen == 0xff { + alen = 0 + } + if slen == 0xff { + slen = 0 + } + l := 4 + nlen + alen + slen + if len(b) < l { + return 0, nil, errInvalidAddr + } + data := b[4:] + var name string + var addr []byte + if nlen > 0 { + name = string(data[:nlen]) + data = data[nlen:] + } + if alen > 0 { + addr = data[:alen] + data = data[alen:] + } + return l, &LinkAddr{Name: name, Addr: addr}, nil +} + +// An Inet4Addr represents an internet address for IPv4. +type Inet4Addr struct { + IP [4]byte // IP address +} + +// Family implements the Family method of Addr interface. +func (a *Inet4Addr) Family() int { return sysAF_INET } + +// An Inet6Addr represents an internet address for IPv6. +type Inet6Addr struct { + IP [16]byte // IP address + ZoneID int // zone identifier +} + +// Family implements the Family method of Addr interface. +func (a *Inet6Addr) Family() int { return sysAF_INET6 } + +// parseInetAddr parses b as an internet address for IPv4 or IPv6. +func parseInetAddr(af int, b []byte) (Addr, error) { + switch af { + case sysAF_INET: + if len(b) < 16 { + return nil, errInvalidAddr + } + a := &Inet4Addr{} + copy(a.IP[:], b[4:8]) + return a, nil + case sysAF_INET6: + if len(b) < 28 { + return nil, errInvalidAddr + } + a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))} + copy(a.IP[:], b[8:24]) + if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) { + // KAME based IPv6 protocol stack usually + // embeds the interface index in the + // interface-local or link-local address as + // the kernel-internal form. + id := int(bigEndian.Uint16(a.IP[2:4])) + if id != 0 { + a.ZoneID = id + a.IP[2], a.IP[3] = 0, 0 + } + } + return a, nil + default: + return nil, errInvalidAddr + } +} + +// parseKernelInetAddr parses b as an internet address in conventional +// BSD kernel form. +func parseKernelInetAddr(af int, b []byte) (int, Addr, error) { + // The encoding looks similar to the NLRI encoding. + // +----------------------------+ + // | Length (1 octet) | + // +----------------------------+ + // | Address prefix (variable) | + // +----------------------------+ + // + // The differences between the kernel form and the NLRI + // encoding are: + // + // - The length field of the kernel form indicates the prefix + // length in bytes, not in bits + // + // - In the kernel form, zero value of the length field + // doesn't mean 0.0.0.0/0 or ::/0 + // + // - The kernel form appends leading bytes to the prefix field + // to make the tuple to be conformed with + // the routing message boundary + l := int(b[0]) + if runtime.GOOS == "darwin" { + // On Darwn, an address in the kernel form is also + // used as a message filler. + if l == 0 || len(b) > roundup(l) { + l = roundup(l) + } + } else { + l = roundup(l) + } + if len(b) < l { + return 0, nil, errInvalidAddr + } + // Don't reorder case expressions. + // The case expressions for IPv6 must come first. + const ( + off4 = 4 // offset of in_addr + off6 = 8 // offset of in6_addr + ) + switch { + case b[0] == 28: // size of sockaddr_in6 + a := &Inet6Addr{} + copy(a.IP[:], b[off6:off6+16]) + return int(b[0]), a, nil + case af == sysAF_INET6: + a := &Inet6Addr{} + if l-1 < off6 { + copy(a.IP[:], b[1:l]) + } else { + copy(a.IP[:], b[l-off6:l]) + } + return int(b[0]), a, nil + case b[0] == 16: // size of sockaddr_in + a := &Inet4Addr{} + copy(a.IP[:], b[off4:off4+4]) + return int(b[0]), a, nil + default: // an old fashion, AF_UNSPEC or unknown means AF_INET + a := &Inet4Addr{} + if l-1 < off4 { + copy(a.IP[:], b[1:l]) + } else { + copy(a.IP[:], b[l-off4:l]) + } + return int(b[0]), a, nil + } +} + +// A DefaultAddr represents an address of various operating +// system-specific features. +type DefaultAddr struct { + af int + Raw []byte // raw format of address +} + +// Family implements the Family method of Addr interface. +func (a *DefaultAddr) Family() int { return a.af } + +func parseDefaultAddr(b []byte) (Addr, error) { + if len(b) < 2 || len(b) < int(b[0]) { + return nil, errInvalidAddr + } + a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]} + return a, nil +} + +func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) { + var as [sysRTAX_MAX]Addr + af := int(sysAF_UNSPEC) + for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ { + if attrs&(1<> 8) +} + +func (binaryLittleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (binaryLittleEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) +} + +func (binaryLittleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +type binaryBigEndian struct{} + +func (binaryBigEndian) Uint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[1]) | uint16(b[0])<<8 +} + +func (binaryBigEndian) PutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 8) + b[1] = byte(v) +} + +func (binaryBigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (binaryBigEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) +} + +func (binaryBigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} diff --git a/src/vendor/golang.org/x/net/route/defs_darwin.go b/src/vendor/golang.org/x/net/route/defs_darwin.go new file mode 100644 index 00000000000000..f452ad14ce6c00 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/defs_darwin.go @@ -0,0 +1,106 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package route + +/* +#include +#include + +#include +#include +#include +*/ +import "C" + +const ( + sysAF_UNSPEC = C.AF_UNSPEC + sysAF_INET = C.AF_INET + sysAF_ROUTE = C.AF_ROUTE + sysAF_LINK = C.AF_LINK + sysAF_INET6 = C.AF_INET6 + + sysNET_RT_DUMP = C.NET_RT_DUMP + sysNET_RT_FLAGS = C.NET_RT_FLAGS + sysNET_RT_IFLIST = C.NET_RT_IFLIST + sysNET_RT_STAT = C.NET_RT_STAT + sysNET_RT_TRASH = C.NET_RT_TRASH + sysNET_RT_IFLIST2 = C.NET_RT_IFLIST2 + sysNET_RT_DUMP2 = C.NET_RT_DUMP2 + sysNET_RT_MAXID = C.NET_RT_MAXID +) + +const ( + sysCTL_MAXNAME = C.CTL_MAXNAME + + sysCTL_UNSPEC = C.CTL_UNSPEC + sysCTL_KERN = C.CTL_KERN + sysCTL_VM = C.CTL_VM + sysCTL_VFS = C.CTL_VFS + sysCTL_NET = C.CTL_NET + sysCTL_DEBUG = C.CTL_DEBUG + sysCTL_HW = C.CTL_HW + sysCTL_MACHDEP = C.CTL_MACHDEP + sysCTL_USER = C.CTL_USER + sysCTL_MAXID = C.CTL_MAXID +) + +const ( + sysRTM_VERSION = C.RTM_VERSION + + sysRTM_ADD = C.RTM_ADD + sysRTM_DELETE = C.RTM_DELETE + sysRTM_CHANGE = C.RTM_CHANGE + sysRTM_GET = C.RTM_GET + sysRTM_LOSING = C.RTM_LOSING + sysRTM_REDIRECT = C.RTM_REDIRECT + sysRTM_MISS = C.RTM_MISS + sysRTM_LOCK = C.RTM_LOCK + sysRTM_OLDADD = C.RTM_OLDADD + sysRTM_OLDDEL = C.RTM_OLDDEL + sysRTM_RESOLVE = C.RTM_RESOLVE + sysRTM_NEWADDR = C.RTM_NEWADDR + sysRTM_DELADDR = C.RTM_DELADDR + sysRTM_IFINFO = C.RTM_IFINFO + sysRTM_NEWMADDR = C.RTM_NEWMADDR + sysRTM_DELMADDR = C.RTM_DELMADDR + sysRTM_IFINFO2 = C.RTM_IFINFO2 + sysRTM_NEWMADDR2 = C.RTM_NEWMADDR2 + sysRTM_GET2 = C.RTM_GET2 + + sysRTA_DST = C.RTA_DST + sysRTA_GATEWAY = C.RTA_GATEWAY + sysRTA_NETMASK = C.RTA_NETMASK + sysRTA_GENMASK = C.RTA_GENMASK + sysRTA_IFP = C.RTA_IFP + sysRTA_IFA = C.RTA_IFA + sysRTA_AUTHOR = C.RTA_AUTHOR + sysRTA_BRD = C.RTA_BRD + + sysRTAX_DST = C.RTAX_DST + sysRTAX_GATEWAY = C.RTAX_GATEWAY + sysRTAX_NETMASK = C.RTAX_NETMASK + sysRTAX_GENMASK = C.RTAX_GENMASK + sysRTAX_IFP = C.RTAX_IFP + sysRTAX_IFA = C.RTAX_IFA + sysRTAX_AUTHOR = C.RTAX_AUTHOR + sysRTAX_BRD = C.RTAX_BRD + sysRTAX_MAX = C.RTAX_MAX +) + +const ( + sizeofIfMsghdrDarwin15 = C.sizeof_struct_if_msghdr + sizeofIfaMsghdrDarwin15 = C.sizeof_struct_ifa_msghdr + sizeofIfmaMsghdrDarwin15 = C.sizeof_struct_ifma_msghdr + sizeofIfMsghdr2Darwin15 = C.sizeof_struct_if_msghdr2 + sizeofIfmaMsghdr2Darwin15 = C.sizeof_struct_ifma_msghdr2 + sizeofIfDataDarwin15 = C.sizeof_struct_if_data + sizeofIfData64Darwin15 = C.sizeof_struct_if_data64 + + sizeofRtMsghdrDarwin15 = C.sizeof_struct_rt_msghdr + sizeofRtMsghdr2Darwin15 = C.sizeof_struct_rt_msghdr2 + sizeofRtMetricsDarwin15 = C.sizeof_struct_rt_metrics +) diff --git a/src/vendor/golang.org/x/net/route/defs_dragonfly.go b/src/vendor/golang.org/x/net/route/defs_dragonfly.go new file mode 100644 index 00000000000000..c737751d76df92 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/defs_dragonfly.go @@ -0,0 +1,105 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package route + +/* +#include +#include + +#include +#include +#include +*/ +import "C" + +const ( + sysAF_UNSPEC = C.AF_UNSPEC + sysAF_INET = C.AF_INET + sysAF_ROUTE = C.AF_ROUTE + sysAF_LINK = C.AF_LINK + sysAF_INET6 = C.AF_INET6 + + sysNET_RT_DUMP = C.NET_RT_DUMP + sysNET_RT_FLAGS = C.NET_RT_FLAGS + sysNET_RT_IFLIST = C.NET_RT_IFLIST + sysNET_RT_MAXID = C.NET_RT_MAXID +) + +const ( + sysCTL_MAXNAME = C.CTL_MAXNAME + + sysCTL_UNSPEC = C.CTL_UNSPEC + sysCTL_KERN = C.CTL_KERN + sysCTL_VM = C.CTL_VM + sysCTL_VFS = C.CTL_VFS + sysCTL_NET = C.CTL_NET + sysCTL_DEBUG = C.CTL_DEBUG + sysCTL_HW = C.CTL_HW + sysCTL_MACHDEP = C.CTL_MACHDEP + sysCTL_USER = C.CTL_USER + sysCTL_P1003_1B = C.CTL_P1003_1B + sysCTL_LWKT = C.CTL_LWKT + sysCTL_MAXID = C.CTL_MAXID +) + +const ( + sysRTM_VERSION = C.RTM_VERSION + + sysRTM_ADD = C.RTM_ADD + sysRTM_DELETE = C.RTM_DELETE + sysRTM_CHANGE = C.RTM_CHANGE + sysRTM_GET = C.RTM_GET + sysRTM_LOSING = C.RTM_LOSING + sysRTM_REDIRECT = C.RTM_REDIRECT + sysRTM_MISS = C.RTM_MISS + sysRTM_LOCK = C.RTM_LOCK + sysRTM_OLDADD = C.RTM_OLDADD + sysRTM_OLDDEL = C.RTM_OLDDEL + sysRTM_RESOLVE = C.RTM_RESOLVE + sysRTM_NEWADDR = C.RTM_NEWADDR + sysRTM_DELADDR = C.RTM_DELADDR + sysRTM_IFINFO = C.RTM_IFINFO + sysRTM_NEWMADDR = C.RTM_NEWMADDR + sysRTM_DELMADDR = C.RTM_DELMADDR + sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE + sysRTM_IEEE80211 = C.RTM_IEEE80211 + + sysRTA_DST = C.RTA_DST + sysRTA_GATEWAY = C.RTA_GATEWAY + sysRTA_NETMASK = C.RTA_NETMASK + sysRTA_GENMASK = C.RTA_GENMASK + sysRTA_IFP = C.RTA_IFP + sysRTA_IFA = C.RTA_IFA + sysRTA_AUTHOR = C.RTA_AUTHOR + sysRTA_BRD = C.RTA_BRD + sysRTA_MPLS1 = C.RTA_MPLS1 + sysRTA_MPLS2 = C.RTA_MPLS2 + sysRTA_MPLS3 = C.RTA_MPLS3 + + sysRTAX_DST = C.RTAX_DST + sysRTAX_GATEWAY = C.RTAX_GATEWAY + sysRTAX_NETMASK = C.RTAX_NETMASK + sysRTAX_GENMASK = C.RTAX_GENMASK + sysRTAX_IFP = C.RTAX_IFP + sysRTAX_IFA = C.RTAX_IFA + sysRTAX_AUTHOR = C.RTAX_AUTHOR + sysRTAX_BRD = C.RTAX_BRD + sysRTAX_MPLS1 = C.RTAX_MPLS1 + sysRTAX_MPLS2 = C.RTAX_MPLS2 + sysRTAX_MPLS3 = C.RTAX_MPLS3 + sysRTAX_MAX = C.RTAX_MAX +) + +const ( + sizeofIfMsghdrDragonFlyBSD4 = C.sizeof_struct_if_msghdr + sizeofIfaMsghdrDragonFlyBSD4 = C.sizeof_struct_ifa_msghdr + sizeofIfmaMsghdrDragonFlyBSD4 = C.sizeof_struct_ifma_msghdr + sizeofIfAnnouncemsghdrDragonFlyBSD4 = C.sizeof_struct_if_announcemsghdr + + sizeofRtMsghdrDragonFlyBSD4 = C.sizeof_struct_rt_msghdr + sizeofRtMetricsDragonFlyBSD4 = C.sizeof_struct_rt_metrics +) diff --git a/src/vendor/golang.org/x/net/route/defs_freebsd.go b/src/vendor/golang.org/x/net/route/defs_freebsd.go new file mode 100644 index 00000000000000..8f834e81db5557 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/defs_freebsd.go @@ -0,0 +1,329 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package route + +/* +#include +#include + +#include +#include +#include + +struct if_data_freebsd7 { + u_char ifi_type; + u_char ifi_physical; + u_char ifi_addrlen; + u_char ifi_hdrlen; + u_char ifi_link_state; + u_char ifi_spare_char1; + u_char ifi_spare_char2; + u_char ifi_datalen; + u_long ifi_mtu; + u_long ifi_metric; + u_long ifi_baudrate; + u_long ifi_ipackets; + u_long ifi_ierrors; + u_long ifi_opackets; + u_long ifi_oerrors; + u_long ifi_collisions; + u_long ifi_ibytes; + u_long ifi_obytes; + u_long ifi_imcasts; + u_long ifi_omcasts; + u_long ifi_iqdrops; + u_long ifi_noproto; + u_long ifi_hwassist; + time_t __ifi_epoch; + struct timeval __ifi_lastchange; +}; + +struct if_data_freebsd8 { + u_char ifi_type; + u_char ifi_physical; + u_char ifi_addrlen; + u_char ifi_hdrlen; + u_char ifi_link_state; + u_char ifi_spare_char1; + u_char ifi_spare_char2; + u_char ifi_datalen; + u_long ifi_mtu; + u_long ifi_metric; + u_long ifi_baudrate; + u_long ifi_ipackets; + u_long ifi_ierrors; + u_long ifi_opackets; + u_long ifi_oerrors; + u_long ifi_collisions; + u_long ifi_ibytes; + u_long ifi_obytes; + u_long ifi_imcasts; + u_long ifi_omcasts; + u_long ifi_iqdrops; + u_long ifi_noproto; + u_long ifi_hwassist; + time_t __ifi_epoch; + struct timeval __ifi_lastchange; +}; + +struct if_data_freebsd9 { + u_char ifi_type; + u_char ifi_physical; + u_char ifi_addrlen; + u_char ifi_hdrlen; + u_char ifi_link_state; + u_char ifi_spare_char1; + u_char ifi_spare_char2; + u_char ifi_datalen; + u_long ifi_mtu; + u_long ifi_metric; + u_long ifi_baudrate; + u_long ifi_ipackets; + u_long ifi_ierrors; + u_long ifi_opackets; + u_long ifi_oerrors; + u_long ifi_collisions; + u_long ifi_ibytes; + u_long ifi_obytes; + u_long ifi_imcasts; + u_long ifi_omcasts; + u_long ifi_iqdrops; + u_long ifi_noproto; + u_long ifi_hwassist; + time_t __ifi_epoch; + struct timeval __ifi_lastchange; +}; + +struct if_data_freebsd10 { + u_char ifi_type; + u_char ifi_physical; + u_char ifi_addrlen; + u_char ifi_hdrlen; + u_char ifi_link_state; + u_char ifi_vhid; + u_char ifi_baudrate_pf; + u_char ifi_datalen; + u_long ifi_mtu; + u_long ifi_metric; + u_long ifi_baudrate; + u_long ifi_ipackets; + u_long ifi_ierrors; + u_long ifi_opackets; + u_long ifi_oerrors; + u_long ifi_collisions; + u_long ifi_ibytes; + u_long ifi_obytes; + u_long ifi_imcasts; + u_long ifi_omcasts; + u_long ifi_iqdrops; + u_long ifi_noproto; + uint64_t ifi_hwassist; + time_t __ifi_epoch; + struct timeval __ifi_lastchange; +}; + +struct if_data_freebsd11 { + uint8_t ifi_type; + uint8_t ifi_physical; + uint8_t ifi_addrlen; + uint8_t ifi_hdrlen; + uint8_t ifi_link_state; + uint8_t ifi_vhid; + uint16_t ifi_datalen; + uint32_t ifi_mtu; + uint32_t ifi_metric; + uint64_t ifi_baudrate; + uint64_t ifi_ipackets; + uint64_t ifi_ierrors; + uint64_t ifi_opackets; + uint64_t ifi_oerrors; + uint64_t ifi_collisions; + uint64_t ifi_ibytes; + uint64_t ifi_obytes; + uint64_t ifi_imcasts; + uint64_t ifi_omcasts; + uint64_t ifi_iqdrops; + uint64_t ifi_oqdrops; + uint64_t ifi_noproto; + uint64_t ifi_hwassist; + union { + time_t tt; + uint64_t ph; + } __ifi_epoch; + union { + struct timeval tv; + struct { + uint64_t ph1; + uint64_t ph2; + } ph; + } __ifi_lastchange; +}; + +struct if_msghdr_freebsd7 { + u_short ifm_msglen; + u_char ifm_version; + u_char ifm_type; + int ifm_addrs; + int ifm_flags; + u_short ifm_index; + struct if_data_freebsd7 ifm_data; +}; + +struct if_msghdr_freebsd8 { + u_short ifm_msglen; + u_char ifm_version; + u_char ifm_type; + int ifm_addrs; + int ifm_flags; + u_short ifm_index; + struct if_data_freebsd8 ifm_data; +}; + +struct if_msghdr_freebsd9 { + u_short ifm_msglen; + u_char ifm_version; + u_char ifm_type; + int ifm_addrs; + int ifm_flags; + u_short ifm_index; + struct if_data_freebsd9 ifm_data; +}; + +struct if_msghdr_freebsd10 { + u_short ifm_msglen; + u_char ifm_version; + u_char ifm_type; + int ifm_addrs; + int ifm_flags; + u_short ifm_index; + struct if_data_freebsd10 ifm_data; +}; + +struct if_msghdr_freebsd11 { + u_short ifm_msglen; + u_char ifm_version; + u_char ifm_type; + int ifm_addrs; + int ifm_flags; + u_short ifm_index; + struct if_data_freebsd11 ifm_data; +}; +*/ +import "C" + +const ( + sysAF_UNSPEC = C.AF_UNSPEC + sysAF_INET = C.AF_INET + sysAF_ROUTE = C.AF_ROUTE + sysAF_LINK = C.AF_LINK + sysAF_INET6 = C.AF_INET6 + + sysNET_RT_DUMP = C.NET_RT_DUMP + sysNET_RT_FLAGS = C.NET_RT_FLAGS + sysNET_RT_IFLIST = C.NET_RT_IFLIST + sysNET_RT_IFMALIST = C.NET_RT_IFMALIST + sysNET_RT_IFLISTL = C.NET_RT_IFLISTL +) + +const ( + sysCTL_MAXNAME = C.CTL_MAXNAME + + sysCTL_UNSPEC = C.CTL_UNSPEC + sysCTL_KERN = C.CTL_KERN + sysCTL_VM = C.CTL_VM + sysCTL_VFS = C.CTL_VFS + sysCTL_NET = C.CTL_NET + sysCTL_DEBUG = C.CTL_DEBUG + sysCTL_HW = C.CTL_HW + sysCTL_MACHDEP = C.CTL_MACHDEP + sysCTL_USER = C.CTL_USER + sysCTL_P1003_1B = C.CTL_P1003_1B +) + +const ( + sysRTM_VERSION = C.RTM_VERSION + + sysRTM_ADD = C.RTM_ADD + sysRTM_DELETE = C.RTM_DELETE + sysRTM_CHANGE = C.RTM_CHANGE + sysRTM_GET = C.RTM_GET + sysRTM_LOSING = C.RTM_LOSING + sysRTM_REDIRECT = C.RTM_REDIRECT + sysRTM_MISS = C.RTM_MISS + sysRTM_LOCK = C.RTM_LOCK + sysRTM_RESOLVE = C.RTM_RESOLVE + sysRTM_NEWADDR = C.RTM_NEWADDR + sysRTM_DELADDR = C.RTM_DELADDR + sysRTM_IFINFO = C.RTM_IFINFO + sysRTM_NEWMADDR = C.RTM_NEWMADDR + sysRTM_DELMADDR = C.RTM_DELMADDR + sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE + sysRTM_IEEE80211 = C.RTM_IEEE80211 + + sysRTA_DST = C.RTA_DST + sysRTA_GATEWAY = C.RTA_GATEWAY + sysRTA_NETMASK = C.RTA_NETMASK + sysRTA_GENMASK = C.RTA_GENMASK + sysRTA_IFP = C.RTA_IFP + sysRTA_IFA = C.RTA_IFA + sysRTA_AUTHOR = C.RTA_AUTHOR + sysRTA_BRD = C.RTA_BRD + + sysRTAX_DST = C.RTAX_DST + sysRTAX_GATEWAY = C.RTAX_GATEWAY + sysRTAX_NETMASK = C.RTAX_NETMASK + sysRTAX_GENMASK = C.RTAX_GENMASK + sysRTAX_IFP = C.RTAX_IFP + sysRTAX_IFA = C.RTAX_IFA + sysRTAX_AUTHOR = C.RTAX_AUTHOR + sysRTAX_BRD = C.RTAX_BRD + sysRTAX_MAX = C.RTAX_MAX +) + +const ( + sizeofIfMsghdrlFreeBSD10 = C.sizeof_struct_if_msghdrl + sizeofIfaMsghdrFreeBSD10 = C.sizeof_struct_ifa_msghdr + sizeofIfaMsghdrlFreeBSD10 = C.sizeof_struct_ifa_msghdrl + sizeofIfmaMsghdrFreeBSD10 = C.sizeof_struct_ifma_msghdr + sizeofIfAnnouncemsghdrFreeBSD10 = C.sizeof_struct_if_announcemsghdr + + sizeofRtMsghdrFreeBSD10 = C.sizeof_struct_rt_msghdr + sizeofRtMetricsFreeBSD10 = C.sizeof_struct_rt_metrics + + sizeofIfMsghdrFreeBSD7 = C.sizeof_struct_if_msghdr_freebsd7 + sizeofIfMsghdrFreeBSD8 = C.sizeof_struct_if_msghdr_freebsd8 + sizeofIfMsghdrFreeBSD9 = C.sizeof_struct_if_msghdr_freebsd9 + sizeofIfMsghdrFreeBSD10 = C.sizeof_struct_if_msghdr_freebsd10 + sizeofIfMsghdrFreeBSD11 = C.sizeof_struct_if_msghdr_freebsd11 + + sizeofIfDataFreeBSD7 = C.sizeof_struct_if_data_freebsd7 + sizeofIfDataFreeBSD8 = C.sizeof_struct_if_data_freebsd8 + sizeofIfDataFreeBSD9 = C.sizeof_struct_if_data_freebsd9 + sizeofIfDataFreeBSD10 = C.sizeof_struct_if_data_freebsd10 + sizeofIfDataFreeBSD11 = C.sizeof_struct_if_data_freebsd11 + + sizeofIfMsghdrlFreeBSD10Emu = C.sizeof_struct_if_msghdrl + sizeofIfaMsghdrFreeBSD10Emu = C.sizeof_struct_ifa_msghdr + sizeofIfaMsghdrlFreeBSD10Emu = C.sizeof_struct_ifa_msghdrl + sizeofIfmaMsghdrFreeBSD10Emu = C.sizeof_struct_ifma_msghdr + sizeofIfAnnouncemsghdrFreeBSD10Emu = C.sizeof_struct_if_announcemsghdr + + sizeofRtMsghdrFreeBSD10Emu = C.sizeof_struct_rt_msghdr + sizeofRtMetricsFreeBSD10Emu = C.sizeof_struct_rt_metrics + + sizeofIfMsghdrFreeBSD7Emu = C.sizeof_struct_if_msghdr_freebsd7 + sizeofIfMsghdrFreeBSD8Emu = C.sizeof_struct_if_msghdr_freebsd8 + sizeofIfMsghdrFreeBSD9Emu = C.sizeof_struct_if_msghdr_freebsd9 + sizeofIfMsghdrFreeBSD10Emu = C.sizeof_struct_if_msghdr_freebsd10 + sizeofIfMsghdrFreeBSD11Emu = C.sizeof_struct_if_msghdr_freebsd11 + + sizeofIfDataFreeBSD7Emu = C.sizeof_struct_if_data_freebsd7 + sizeofIfDataFreeBSD8Emu = C.sizeof_struct_if_data_freebsd8 + sizeofIfDataFreeBSD9Emu = C.sizeof_struct_if_data_freebsd9 + sizeofIfDataFreeBSD10Emu = C.sizeof_struct_if_data_freebsd10 + sizeofIfDataFreeBSD11Emu = C.sizeof_struct_if_data_freebsd11 +) diff --git a/src/vendor/golang.org/x/net/route/defs_netbsd.go b/src/vendor/golang.org/x/net/route/defs_netbsd.go new file mode 100644 index 00000000000000..b18d85e0165db9 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/defs_netbsd.go @@ -0,0 +1,104 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package route + +/* +#include +#include + +#include +#include +#include +*/ +import "C" + +const ( + sysAF_UNSPEC = C.AF_UNSPEC + sysAF_INET = C.AF_INET + sysAF_ROUTE = C.AF_ROUTE + sysAF_LINK = C.AF_LINK + sysAF_INET6 = C.AF_INET6 + + sysNET_RT_DUMP = C.NET_RT_DUMP + sysNET_RT_FLAGS = C.NET_RT_FLAGS + sysNET_RT_IFLIST = C.NET_RT_IFLIST + sysNET_RT_MAXID = C.NET_RT_MAXID +) + +const ( + sysCTL_MAXNAME = C.CTL_MAXNAME + + sysCTL_UNSPEC = C.CTL_UNSPEC + sysCTL_KERN = C.CTL_KERN + sysCTL_VM = C.CTL_VM + sysCTL_VFS = C.CTL_VFS + sysCTL_NET = C.CTL_NET + sysCTL_DEBUG = C.CTL_DEBUG + sysCTL_HW = C.CTL_HW + sysCTL_MACHDEP = C.CTL_MACHDEP + sysCTL_USER = C.CTL_USER + sysCTL_DDB = C.CTL_DDB + sysCTL_PROC = C.CTL_PROC + sysCTL_VENDOR = C.CTL_VENDOR + sysCTL_EMUL = C.CTL_EMUL + sysCTL_SECURITY = C.CTL_SECURITY + sysCTL_MAXID = C.CTL_MAXID +) + +const ( + sysRTM_VERSION = C.RTM_VERSION + + sysRTM_ADD = C.RTM_ADD + sysRTM_DELETE = C.RTM_DELETE + sysRTM_CHANGE = C.RTM_CHANGE + sysRTM_GET = C.RTM_GET + sysRTM_LOSING = C.RTM_LOSING + sysRTM_REDIRECT = C.RTM_REDIRECT + sysRTM_MISS = C.RTM_MISS + sysRTM_LOCK = C.RTM_LOCK + sysRTM_OLDADD = C.RTM_OLDADD + sysRTM_OLDDEL = C.RTM_OLDDEL + sysRTM_RESOLVE = C.RTM_RESOLVE + sysRTM_NEWADDR = C.RTM_NEWADDR + sysRTM_DELADDR = C.RTM_DELADDR + sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE + sysRTM_IEEE80211 = C.RTM_IEEE80211 + sysRTM_SETGATE = C.RTM_SETGATE + sysRTM_LLINFO_UPD = C.RTM_LLINFO_UPD + sysRTM_IFINFO = C.RTM_IFINFO + sysRTM_CHGADDR = C.RTM_CHGADDR + + sysRTA_DST = C.RTA_DST + sysRTA_GATEWAY = C.RTA_GATEWAY + sysRTA_NETMASK = C.RTA_NETMASK + sysRTA_GENMASK = C.RTA_GENMASK + sysRTA_IFP = C.RTA_IFP + sysRTA_IFA = C.RTA_IFA + sysRTA_AUTHOR = C.RTA_AUTHOR + sysRTA_BRD = C.RTA_BRD + sysRTA_TAG = C.RTA_TAG + + sysRTAX_DST = C.RTAX_DST + sysRTAX_GATEWAY = C.RTAX_GATEWAY + sysRTAX_NETMASK = C.RTAX_NETMASK + sysRTAX_GENMASK = C.RTAX_GENMASK + sysRTAX_IFP = C.RTAX_IFP + sysRTAX_IFA = C.RTAX_IFA + sysRTAX_AUTHOR = C.RTAX_AUTHOR + sysRTAX_BRD = C.RTAX_BRD + sysRTAX_TAG = C.RTAX_TAG + sysRTAX_MAX = C.RTAX_MAX +) + +const ( + sizeofIfMsghdrNetBSD7 = C.sizeof_struct_if_msghdr + sizeofIfaMsghdrNetBSD7 = C.sizeof_struct_ifa_msghdr + sizeofIfAnnouncemsghdrNetBSD7 = C.sizeof_struct_if_announcemsghdr + + sizeofRtMsghdrNetBSD7 = C.sizeof_struct_rt_msghdr + sizeofRtMetricsNetBSD7 = C.sizeof_struct_rt_metrics +) diff --git a/src/vendor/golang.org/x/net/route/defs_openbsd.go b/src/vendor/golang.org/x/net/route/defs_openbsd.go new file mode 100644 index 00000000000000..5df7a43bc3ee64 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/defs_openbsd.go @@ -0,0 +1,93 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package route + +/* +#include +#include + +#include +#include +#include +*/ +import "C" + +const ( + sysAF_UNSPEC = C.AF_UNSPEC + sysAF_INET = C.AF_INET + sysAF_ROUTE = C.AF_ROUTE + sysAF_LINK = C.AF_LINK + sysAF_INET6 = C.AF_INET6 + + sysNET_RT_DUMP = C.NET_RT_DUMP + sysNET_RT_FLAGS = C.NET_RT_FLAGS + sysNET_RT_IFLIST = C.NET_RT_IFLIST + sysNET_RT_STATS = C.NET_RT_STATS + sysNET_RT_TABLE = C.NET_RT_TABLE + sysNET_RT_IFNAMES = C.NET_RT_IFNAMES + sysNET_RT_MAXID = C.NET_RT_MAXID +) + +const ( + sysCTL_MAXNAME = C.CTL_MAXNAME + + sysCTL_UNSPEC = C.CTL_UNSPEC + sysCTL_KERN = C.CTL_KERN + sysCTL_VM = C.CTL_VM + sysCTL_FS = C.CTL_FS + sysCTL_NET = C.CTL_NET + sysCTL_DEBUG = C.CTL_DEBUG + sysCTL_HW = C.CTL_HW + sysCTL_MACHDEP = C.CTL_MACHDEP + sysCTL_DDB = C.CTL_DDB + sysCTL_VFS = C.CTL_VFS + sysCTL_MAXID = C.CTL_MAXID +) + +const ( + sysRTM_VERSION = C.RTM_VERSION + + sysRTM_ADD = C.RTM_ADD + sysRTM_DELETE = C.RTM_DELETE + sysRTM_CHANGE = C.RTM_CHANGE + sysRTM_GET = C.RTM_GET + sysRTM_LOSING = C.RTM_LOSING + sysRTM_REDIRECT = C.RTM_REDIRECT + sysRTM_MISS = C.RTM_MISS + sysRTM_LOCK = C.RTM_LOCK + sysRTM_RESOLVE = C.RTM_RESOLVE + sysRTM_NEWADDR = C.RTM_NEWADDR + sysRTM_DELADDR = C.RTM_DELADDR + sysRTM_IFINFO = C.RTM_IFINFO + sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE + sysRTM_DESYNC = C.RTM_DESYNC + + sysRTA_DST = C.RTA_DST + sysRTA_GATEWAY = C.RTA_GATEWAY + sysRTA_NETMASK = C.RTA_NETMASK + sysRTA_GENMASK = C.RTA_GENMASK + sysRTA_IFP = C.RTA_IFP + sysRTA_IFA = C.RTA_IFA + sysRTA_AUTHOR = C.RTA_AUTHOR + sysRTA_BRD = C.RTA_BRD + sysRTA_SRC = C.RTA_SRC + sysRTA_SRCMASK = C.RTA_SRCMASK + sysRTA_LABEL = C.RTA_LABEL + + sysRTAX_DST = C.RTAX_DST + sysRTAX_GATEWAY = C.RTAX_GATEWAY + sysRTAX_NETMASK = C.RTAX_NETMASK + sysRTAX_GENMASK = C.RTAX_GENMASK + sysRTAX_IFP = C.RTAX_IFP + sysRTAX_IFA = C.RTAX_IFA + sysRTAX_AUTHOR = C.RTAX_AUTHOR + sysRTAX_BRD = C.RTAX_BRD + sysRTAX_SRC = C.RTAX_SRC + sysRTAX_SRCMASK = C.RTAX_SRCMASK + sysRTAX_LABEL = C.RTAX_LABEL + sysRTAX_MAX = C.RTAX_MAX +) diff --git a/src/vendor/golang.org/x/net/route/interface.go b/src/vendor/golang.org/x/net/route/interface.go new file mode 100644 index 00000000000000..854906d9c42913 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface.go @@ -0,0 +1,64 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +// An InterfaceMessage represents an interface message. +type InterfaceMessage struct { + Version int // message version + Type int // message type + Flags int // interface flags + Index int // interface index + Name string // interface name + Addrs []Addr // addresses + + extOff int // offset of header extension + raw []byte // raw message +} + +// An InterfaceAddrMessage represents an interface address message. +type InterfaceAddrMessage struct { + Version int // message version + Type int // message type + Flags int // interface flags + Index int // interface index + Addrs []Addr // addresses + + raw []byte // raw message +} + +// Sys implements the Sys method of Message interface. +func (m *InterfaceAddrMessage) Sys() []Sys { return nil } + +// An InterfaceMulticastAddrMessage represents an interface multicast +// address message. +type InterfaceMulticastAddrMessage struct { + Version int // message version + Type int // messsage type + Flags int // interface flags + Index int // interface index + Addrs []Addr // addresses + + raw []byte // raw message +} + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMulticastAddrMessage) Sys() []Sys { return nil } + +// An InterfaceAnnounceMessage represents an interface announcement +// message. +type InterfaceAnnounceMessage struct { + Version int // message version + Type int // message type + Index int // interface index + Name string // interface name + What int // what type of announcement + + raw []byte // raw message +} + +// Sys implements the Sys method of Message interface. +func (m *InterfaceAnnounceMessage) Sys() []Sys { return nil } diff --git a/src/vendor/golang.org/x/net/route/interface_announce.go b/src/vendor/golang.org/x/net/route/interface_announce.go new file mode 100644 index 00000000000000..520d657b578fce --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface_announce.go @@ -0,0 +1,32 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build dragonfly freebsd netbsd + +package route + +func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &InterfaceAnnounceMessage{ + Version: int(b[2]), + Type: int(b[3]), + Index: int(nativeEndian.Uint16(b[4:6])), + What: int(nativeEndian.Uint16(b[22:24])), + raw: b[:l], + } + for i := 0; i < 16; i++ { + if b[6+i] != 0 { + continue + } + m.Name = string(b[6 : 6+i]) + break + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/interface_classic.go b/src/vendor/golang.org/x/net/route/interface_classic.go new file mode 100644 index 00000000000000..ac4e7a6805afdf --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface_classic.go @@ -0,0 +1,66 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly netbsd + +package route + +import "runtime" + +func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + attrs := uint(nativeEndian.Uint32(b[4:8])) + if attrs&sysRTA_IFP == 0 { + return nil, nil + } + m := &InterfaceMessage{ + Version: int(b[2]), + Type: int(b[3]), + Addrs: make([]Addr, sysRTAX_MAX), + Flags: int(nativeEndian.Uint32(b[8:12])), + Index: int(nativeEndian.Uint16(b[12:14])), + extOff: w.extOff, + raw: b[:l], + } + a, err := parseLinkAddr(b[w.bodyOff:]) + if err != nil { + return nil, err + } + m.Addrs[sysRTAX_IFP] = a + m.Name = a.(*LinkAddr).Name + return m, nil +} + +func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &InterfaceAddrMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[8:12])), + raw: b[:l], + } + if runtime.GOOS == "netbsd" { + m.Index = int(nativeEndian.Uint16(b[16:18])) + } else { + m.Index = int(nativeEndian.Uint16(b[12:14])) + } + var err error + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:]) + if err != nil { + return nil, err + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/interface_freebsd.go b/src/vendor/golang.org/x/net/route/interface_freebsd.go new file mode 100644 index 00000000000000..c83053915da52b --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface_freebsd.go @@ -0,0 +1,78 @@ +// 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 route + +func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, error) { + var extOff, bodyOff int + if typ == sysNET_RT_IFLISTL { + if len(b) < 20 { + return nil, errMessageTooShort + } + extOff = int(nativeEndian.Uint16(b[18:20])) + bodyOff = int(nativeEndian.Uint16(b[16:18])) + } else { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + extOff = w.extOff + bodyOff = w.bodyOff + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + attrs := uint(nativeEndian.Uint32(b[4:8])) + if attrs&sysRTA_IFP == 0 { + return nil, nil + } + m := &InterfaceMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[8:12])), + Index: int(nativeEndian.Uint16(b[12:14])), + Addrs: make([]Addr, sysRTAX_MAX), + extOff: extOff, + raw: b[:l], + } + a, err := parseLinkAddr(b[bodyOff:]) + if err != nil { + return nil, err + } + m.Addrs[sysRTAX_IFP] = a + m.Name = a.(*LinkAddr).Name + return m, nil +} + +func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message, error) { + var bodyOff int + if typ == sysNET_RT_IFLISTL { + if len(b) < 24 { + return nil, errMessageTooShort + } + bodyOff = int(nativeEndian.Uint16(b[16:18])) + } else { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + bodyOff = w.bodyOff + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &InterfaceAddrMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[8:12])), + Index: int(nativeEndian.Uint16(b[12:14])), + raw: b[:l], + } + var err error + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[bodyOff:]) + if err != nil { + return nil, err + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/interface_multicast.go b/src/vendor/golang.org/x/net/route/interface_multicast.go new file mode 100644 index 00000000000000..1e99a9cc64b9ad --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface_multicast.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd + +package route + +func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &InterfaceMulticastAddrMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[8:12])), + Index: int(nativeEndian.Uint16(b[12:14])), + raw: b[:l], + } + var err error + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:]) + if err != nil { + return nil, err + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/interface_openbsd.go b/src/vendor/golang.org/x/net/route/interface_openbsd.go new file mode 100644 index 00000000000000..24451d8ca12067 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/interface_openbsd.go @@ -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 route + +func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < 32 { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + attrs := uint(nativeEndian.Uint32(b[12:16])) + if attrs&sysRTA_IFP == 0 { + return nil, nil + } + m := &InterfaceMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[16:20])), + Index: int(nativeEndian.Uint16(b[6:8])), + Addrs: make([]Addr, sysRTAX_MAX), + raw: b[:l], + } + a, err := parseLinkAddr(b[int(nativeEndian.Uint16(b[4:6])):]) + if err != nil { + return nil, err + } + m.Addrs[sysRTAX_IFP] = a + m.Name = a.(*LinkAddr).Name + return m, nil +} + +func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < 24 { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + bodyOff := int(nativeEndian.Uint16(b[4:6])) + m := &InterfaceAddrMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[12:16])), + Index: int(nativeEndian.Uint16(b[6:8])), + raw: b[:l], + } + var err error + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[bodyOff:]) + if err != nil { + return nil, err + } + return m, nil +} + +func (*wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < 26 { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &InterfaceAnnounceMessage{ + Version: int(b[2]), + Type: int(b[3]), + Index: int(nativeEndian.Uint16(b[6:8])), + What: int(nativeEndian.Uint16(b[8:10])), + raw: b[:l], + } + for i := 0; i < 16; i++ { + if b[10+i] != 0 { + continue + } + m.Name = string(b[10 : 10+i]) + break + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/message.go b/src/vendor/golang.org/x/net/route/message.go new file mode 100644 index 00000000000000..27cbf6b77ace75 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/message.go @@ -0,0 +1,70 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +// A Message represents a routing message. +// +// Note: This interface will be changed to support Marshal method in +// future version. +type Message interface { + // Sys returns operating system-specific information. + Sys() []Sys +} + +// A Sys reprensents operating system-specific information. +type Sys interface { + // SysType returns a type of operating system-specific + // information. + SysType() SysType +} + +// A SysType represents a type of operating system-specific +// information. +type SysType int + +const ( + SysMetrics SysType = iota + SysStats +) + +// ParseRIB parses b as a routing information base and returns a list +// of routing messages. +func ParseRIB(typ RIBType, b []byte) ([]Message, error) { + if !typ.parseable() { + return nil, errUnsupportedMessage + } + var msgs []Message + nmsgs, nskips := 0, 0 + for len(b) > 4 { + nmsgs++ + l := int(nativeEndian.Uint16(b[:2])) + if b[2] != sysRTM_VERSION { + b = b[l:] + continue + } + mtyp := int(b[3]) + if fn, ok := parseFns[mtyp]; !ok { + nskips++ + } else { + m, err := fn(typ, b) + if err != nil { + return nil, err + } + if m == nil { + nskips++ + } else { + msgs = append(msgs, m) + } + } + b = b[l:] + } + // We failed to parse any of the messages - version mismatch? + if nmsgs != len(msgs)+nskips { + return nil, errMessageMismatch + } + return msgs, nil +} diff --git a/src/vendor/golang.org/x/net/route/message_darwin_test.go b/src/vendor/golang.org/x/net/route/message_darwin_test.go new file mode 100644 index 00000000000000..3fdd12df5537e2 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/message_darwin_test.go @@ -0,0 +1,27 @@ +// 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 route + +import "testing" + +func TestFetchAndParseRIBOnDarwin(t *testing.T) { + for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} { + for _, typ := range []RIBType{sysNET_RT_FLAGS, sysNET_RT_DUMP2, sysNET_RT_IFLIST2} { + ms, err := fetchAndParseRIB(af, typ) + if err != nil { + t.Error(err) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Errorf("%v %d %v", addrFamily(af), typ, err) + continue + } + for _, s := range ss { + t.Log(s) + } + } + } +} diff --git a/src/vendor/golang.org/x/net/route/message_freebsd_test.go b/src/vendor/golang.org/x/net/route/message_freebsd_test.go new file mode 100644 index 00000000000000..6d03d000a82fda --- /dev/null +++ b/src/vendor/golang.org/x/net/route/message_freebsd_test.go @@ -0,0 +1,106 @@ +// 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 route + +import ( + "testing" + "time" + "unsafe" +) + +func TestFetchAndParseRIBOnFreeBSD(t *testing.T) { + for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} { + for _, typ := range []RIBType{sysNET_RT_IFMALIST} { + ms, err := fetchAndParseRIB(af, typ) + if err != nil { + t.Error(err) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Errorf("%v %d %v", addrFamily(af), typ, err) + continue + } + for _, s := range ss { + t.Log(s) + } + } + } +} + +func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) { + if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil { + t.Skip("NET_RT_LISTL not supported") + } + var p uintptr + if kernelAlign != int(unsafe.Sizeof(p)) { + t.Skip("NET_RT_LIST vs. NET_RT_LISTL doesn't work for 386 emulation on amd64") + } + + var tests = [2]struct { + typ RIBType + b []byte + msgs []Message + ss []string + }{ + {typ: sysNET_RT_IFLIST}, + {typ: sysNET_RT_IFLISTL}, + } + for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} { + var lastErr error + for i := 0; i < 3; i++ { + for j := range tests { + var err error + if tests[j].b, err = FetchRIB(af, tests[j].typ, 0); err != nil { + lastErr = err + time.Sleep(10 * time.Millisecond) + } + } + if lastErr == nil { + break + } + } + if lastErr != nil { + t.Error(af, lastErr) + continue + } + for i := range tests { + var err error + if tests[i].msgs, err = ParseRIB(tests[i].typ, tests[i].b); err != nil { + lastErr = err + t.Error(af, err) + } + } + if lastErr != nil { + continue + } + for i := range tests { + var err error + tests[i].ss, err = msgs(tests[i].msgs).validate() + if err != nil { + lastErr = err + t.Error(af, err) + } + for _, s := range tests[i].ss { + t.Log(s) + } + } + if lastErr != nil { + continue + } + for i := len(tests) - 1; i > 0; i-- { + if len(tests[i].ss) != len(tests[i-1].ss) { + t.Errorf("got %v; want %v", tests[i].ss, tests[i-1].ss) + continue + } + for j, s1 := range tests[i].ss { + s0 := tests[i-1].ss[j] + if s1 != s0 { + t.Errorf("got %s; want %s", s1, s0) + } + } + } + } +} diff --git a/src/vendor/golang.org/x/net/route/message_test.go b/src/vendor/golang.org/x/net/route/message_test.go new file mode 100644 index 00000000000000..a1263d8f25e4dc --- /dev/null +++ b/src/vendor/golang.org/x/net/route/message_test.go @@ -0,0 +1,95 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +import ( + "os" + "syscall" + "testing" + "time" +) + +func TestFetchAndParseRIB(t *testing.T) { + for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} { + for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} { + ms, err := fetchAndParseRIB(af, typ) + if err != nil { + t.Error(err) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Errorf("%v %d %v", addrFamily(af), typ, err) + continue + } + for _, s := range ss { + t.Log(s) + } + } + } +} + +func TestMonitorAndParseRIB(t *testing.T) { + if testing.Short() || os.Getuid() != 0 { + t.Skip("must be root") + } + + // We suppose that using an IPv4 link-local address and the + // dot1Q ID for Token Ring and FDDI doesn't harm anyone. + pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} + if err := pv.configure(1002); err != nil { + t.Skip(err) + } + if err := pv.setup(); err != nil { + t.Skip(err) + } + pv.teardown() + + s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) + if err != nil { + t.Fatal(err) + } + defer syscall.Close(s) + + go func() { + b := make([]byte, os.Getpagesize()) + for { + n, err := syscall.Read(s, b) + if err != nil { + return + } + ms, err := ParseRIB(0, b[:n]) + if err != nil { + t.Error(err) + return + } + ss, err := msgs(ms).validate() + if err != nil { + t.Error(err) + return + } + for _, s := range ss { + t.Log(s) + } + } + }() + + for _, vid := range []int{1002, 1003, 1004, 1005} { + pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} + if err := pv.configure(vid); err != nil { + t.Fatal(err) + } + if err := pv.setup(); err != nil { + t.Fatal(err) + } + time.Sleep(200 * time.Millisecond) + if err := pv.teardown(); err != nil { + t.Fatal(err) + } + time.Sleep(200 * time.Millisecond) + } +} diff --git a/src/vendor/golang.org/x/net/route/route.go b/src/vendor/golang.org/x/net/route/route.go new file mode 100644 index 00000000000000..c986e29ebc94c3 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/route.go @@ -0,0 +1,74 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +// Package route provides basic functions for the manipulation of +// packet routing facilities on BSD variants. +// +// The package supports any version of Darwin, any version of +// DragonFly BSD, FreeBSD 7 through 11, NetBSD 6 and above, and +// OpenBSD 5.6 and above. +package route + +import ( + "errors" + "os" + "syscall" +) + +var ( + errUnsupportedMessage = errors.New("unsupported message") + errMessageMismatch = errors.New("message mismatch") + errMessageTooShort = errors.New("message too short") + errInvalidMessage = errors.New("invalid message") + errInvalidAddr = errors.New("invalid address") +) + +// A RouteMessage represents a message conveying an address prefix, a +// nexthop address and an output interface. +type RouteMessage struct { + Version int // message version + Type int // message type + Flags int // route flags + Index int // interface index when atatched + Addrs []Addr // addresses + + extOff int // offset of header extension + raw []byte // raw message +} + +// A RIBType reprensents a type of routing information base. +type RIBType int + +const ( + RIBTypeRoute RIBType = syscall.NET_RT_DUMP + RIBTypeInterface RIBType = syscall.NET_RT_IFLIST +) + +// FetchRIB fetches a routing information base from the operating +// system. +// +// The provided af must be an address family. +// +// The provided arg must be a RIBType-specific argument. +// When RIBType is related to routes, arg might be a set of route +// flags. When RIBType is related to network interfaces, arg might be +// an interface index or a set of interface flags. In most cases, zero +// means a wildcard. +func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) { + mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)} + n := uintptr(0) + if err := sysctl(mib[:], nil, &n, nil, 0); err != nil { + return nil, os.NewSyscallError("sysctl", err) + } + if n == 0 { + return nil, nil + } + b := make([]byte, n) + if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil { + return nil, os.NewSyscallError("sysctl", err) + } + return b[:n], nil +} diff --git a/src/vendor/golang.org/x/net/route/route_classic.go b/src/vendor/golang.org/x/net/route/route_classic.go new file mode 100644 index 00000000000000..d333c6aa526b19 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/route_classic.go @@ -0,0 +1,31 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd + +package route + +func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) { + if len(b) < w.bodyOff { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &RouteMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[8:12])), + Index: int(nativeEndian.Uint16(b[4:6])), + extOff: w.extOff, + raw: b[:l], + } + var err error + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:]) + if err != nil { + return nil, err + } + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/route_openbsd.go b/src/vendor/golang.org/x/net/route/route_openbsd.go new file mode 100644 index 00000000000000..b07862f04d3f50 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/route_openbsd.go @@ -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 route + +func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) { + if len(b) < 40 { + return nil, errMessageTooShort + } + l := int(nativeEndian.Uint16(b[:2])) + if len(b) < l { + return nil, errInvalidMessage + } + m := &RouteMessage{ + Version: int(b[2]), + Type: int(b[3]), + Flags: int(nativeEndian.Uint32(b[16:20])), + Index: int(nativeEndian.Uint16(b[6:8])), + raw: b[:l], + } + as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[int(nativeEndian.Uint16(b[4:6])):]) + if err != nil { + return nil, err + } + m.Addrs = as + return m, nil +} diff --git a/src/vendor/golang.org/x/net/route/route_test.go b/src/vendor/golang.org/x/net/route/route_test.go new file mode 100644 index 00000000000000..99f57b712d9c38 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/route_test.go @@ -0,0 +1,385 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +import ( + "fmt" + "os/exec" + "runtime" + "time" +) + +func (m *RouteMessage) String() string { + return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16]))) +} + +func (m *InterfaceMessage) String() string { + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + return fmt.Sprintf("%s", attrs) +} + +func (m *InterfaceAddrMessage) String() string { + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + return fmt.Sprintf("%s", attrs) +} + +func (m *InterfaceMulticastAddrMessage) String() string { + return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8]))) +} + +func (m *InterfaceAnnounceMessage) String() string { + what := "" + switch m.What { + case 0: + what = "arrival" + case 1: + what = "departure" + } + return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what) +} + +func (m *InterfaceMetrics) String() string { + return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU) +} + +func (m *RouteMetrics) String() string { + return fmt.Sprintf("(pmtu=%d)", m.PathMTU) +} + +type addrAttrs uint + +var addrAttrNames = [...]string{ + "dst", + "gateway", + "netmask", + "genmask", + "ifp", + "ifa", + "author", + "brd", + "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd + "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd + "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd +} + +func (attrs addrAttrs) String() string { + var s string + for i, name := range addrAttrNames { + if attrs&(1<" + } + return s +} + +type msgs []Message + +func (ms msgs) validate() ([]string, error) { + var ss []string + for _, m := range ms { + switch m := m.(type) { + case *RouteMessage: + if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil { + return nil, err + } + sys := m.Sys() + if sys == nil { + return nil, fmt.Errorf("no sys for %s", m.String()) + } + ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) + case *InterfaceMessage: + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + if err := addrs(m.Addrs).match(attrs); err != nil { + return nil, err + } + sys := m.Sys() + if sys == nil { + return nil, fmt.Errorf("no sys for %s", m.String()) + } + ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) + case *InterfaceAddrMessage: + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + if err := addrs(m.Addrs).match(attrs); err != nil { + return nil, err + } + ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) + case *InterfaceMulticastAddrMessage: + if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil { + return nil, err + } + ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) + case *InterfaceAnnounceMessage: + ss = append(ss, m.String()) + default: + ss = append(ss, fmt.Sprintf("%+v", m)) + } + } + return ss, nil +} + +type syss []Sys + +func (sys syss) String() string { + var s string + for _, sy := range sys { + switch sy := sy.(type) { + case *InterfaceMetrics: + if len(s) > 0 { + s += " " + } + s += sy.String() + case *RouteMetrics: + if len(s) > 0 { + s += " " + } + s += sy.String() + } + } + return s +} + +type addrFamily int + +func (af addrFamily) String() string { + switch af { + case sysAF_UNSPEC: + return "unspec" + case sysAF_LINK: + return "link" + case sysAF_INET: + return "inet4" + case sysAF_INET6: + return "inet6" + default: + return fmt.Sprintf("%d", af) + } +} + +const hexDigit = "0123456789abcdef" + +type llAddr []byte + +func (a llAddr) String() string { + if len(a) == 0 { + return "" + } + buf := make([]byte, 0, len(a)*3-1) + for i, b := range a { + if i > 0 { + buf = append(buf, ':') + } + buf = append(buf, hexDigit[b>>4]) + buf = append(buf, hexDigit[b&0xF]) + } + return string(buf) +} + +type ipAddr []byte + +func (a ipAddr) String() string { + if len(a) == 0 { + return "" + } + if len(a) == 4 { + return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3]) + } + if len(a) == 16 { + return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]) + } + s := make([]byte, len(a)*2) + for i, tn := range a { + s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf] + } + return string(s) +} + +func (a *LinkAddr) String() string { + name := a.Name + if name == "" { + name = "" + } + lla := llAddr(a.Addr).String() + if lla == "" { + lla = "" + } + return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla) +} + +func (a Inet4Addr) String() string { + return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:])) +} + +func (a *Inet6Addr) String() string { + return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID) +} + +func (a *DefaultAddr) String() string { + return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String()) +} + +type addrs []Addr + +func (as addrs) String() string { + var s string + for _, a := range as { + if a == nil { + continue + } + if len(s) > 0 { + s += " " + } + switch a := a.(type) { + case *LinkAddr: + s += a.String() + case *Inet4Addr: + s += a.String() + case *Inet6Addr: + s += a.String() + case *DefaultAddr: + s += a.String() + } + } + if s == "" { + return "" + } + return s +} + +func (as addrs) match(attrs addrAttrs) error { + var ts addrAttrs + af := sysAF_UNSPEC + for i := range as { + if as[i] != nil { + ts |= 1 << uint(i) + } + switch as[i].(type) { + case *Inet4Addr: + if af == sysAF_UNSPEC { + af = sysAF_INET + } + if af != sysAF_INET { + return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) + } + case *Inet6Addr: + if af == sysAF_UNSPEC { + af = sysAF_INET6 + } + if af != sysAF_INET6 { + return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) + } + } + } + if ts != attrs && ts > attrs { + return fmt.Errorf("%v not included in %v", ts, attrs) + } + return nil +} + +func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) { + var err error + var b []byte + for i := 0; i < 3; i++ { + if b, err = FetchRIB(af, typ, 0); err != nil { + time.Sleep(10 * time.Millisecond) + continue + } + break + } + if err != nil { + return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) + } + ms, err := ParseRIB(typ, b) + if err != nil { + return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) + } + return ms, nil +} + +type propVirtual struct { + name string + addr, mask string + setupCmds []*exec.Cmd + teardownCmds []*exec.Cmd +} + +func (ti *propVirtual) setup() error { + for _, cmd := range ti.setupCmds { + if err := cmd.Run(); err != nil { + ti.teardown() + return err + } + } + return nil +} + +func (ti *propVirtual) teardown() error { + for _, cmd := range ti.teardownCmds { + if err := cmd.Run(); err != nil { + return err + } + } + return nil +} + +func (ti *propVirtual) configure(suffix int) error { + if runtime.GOOS == "openbsd" { + ti.name = fmt.Sprintf("vether%d", suffix) + } else { + ti.name = fmt.Sprintf("vlan%d", suffix) + } + xname, err := exec.LookPath("ifconfig") + if err != nil { + return err + } + ti.setupCmds = append(ti.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", ti.name, "create"}, + }) + if runtime.GOOS == "netbsd" { + // NetBSD requires an underlying dot1Q-capable network + // interface. + ti.setupCmds = append(ti.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", ti.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"}, + }) + } + ti.setupCmds = append(ti.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", ti.name, "inet", ti.addr, "netmask", ti.mask}, + }) + ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", ti.name, "destroy"}, + }) + return nil +} diff --git a/src/vendor/golang.org/x/net/route/sys.go b/src/vendor/golang.org/x/net/route/sys.go new file mode 100644 index 00000000000000..80ca83ae1378fe --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys.go @@ -0,0 +1,40 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +import "unsafe" + +var ( + nativeEndian binaryByteOrder + kernelAlign int + parseFns map[int]parseFn +) + +func init() { + i := uint32(1) + b := (*[4]byte)(unsafe.Pointer(&i)) + if b[0] == 1 { + nativeEndian = littleEndian + } else { + nativeEndian = bigEndian + } + kernelAlign, parseFns = probeRoutingStack() +} + +func roundup(l int) int { + if l == 0 { + return kernelAlign + } + return (l + kernelAlign - 1) & ^(kernelAlign - 1) +} + +type parseFn func(RIBType, []byte) (Message, error) + +type wireFormat struct { + extOff int // offset of header extension + bodyOff int // offset of message body +} diff --git a/src/vendor/golang.org/x/net/route/sys_darwin.go b/src/vendor/golang.org/x/net/route/sys_darwin.go new file mode 100644 index 00000000000000..fff3a0fd1db29a --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys_darwin.go @@ -0,0 +1,80 @@ +// 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 route + +func (typ RIBType) parseable() bool { + switch typ { + case sysNET_RT_STAT, sysNET_RT_TRASH: + return false + default: + return true + } +} + +// A RouteMetrics represents route metrics. +type RouteMetrics struct { + PathMTU int // path maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *RouteMessage) Sys() []Sys { + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])), + }, + } +} + +// A InterfaceMetrics represents interface metrics. +type InterfaceMetrics struct { + Type int // interface type + MTU int // maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMessage) Sys() []Sys { + return []Sys{ + &InterfaceMetrics{ + Type: int(m.raw[m.extOff]), + MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), + }, + } +} + +func probeRoutingStack() (int, map[int]parseFn) { + rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15} + rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15} + ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15} + ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15} + ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15} + ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15} + ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15} + // Darwin kernels require 32-bit aligned access to routing facilities. + return 4, map[int]parseFn{ + sysRTM_ADD: rtm.parseRouteMessage, + sysRTM_DELETE: rtm.parseRouteMessage, + sysRTM_CHANGE: rtm.parseRouteMessage, + sysRTM_GET: rtm.parseRouteMessage, + sysRTM_LOSING: rtm.parseRouteMessage, + sysRTM_REDIRECT: rtm.parseRouteMessage, + sysRTM_MISS: rtm.parseRouteMessage, + sysRTM_LOCK: rtm.parseRouteMessage, + sysRTM_RESOLVE: rtm.parseRouteMessage, + sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage, + sysRTM_DELADDR: ifam.parseInterfaceAddrMessage, + sysRTM_IFINFO: ifm.parseInterfaceMessage, + sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_IFINFO2: ifm2.parseInterfaceMessage, + sysRTM_NEWMADDR2: ifmam2.parseInterfaceMulticastAddrMessage, + sysRTM_GET2: rtm2.parseRouteMessage, + } +} diff --git a/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/src/vendor/golang.org/x/net/route/sys_dragonfly.go new file mode 100644 index 00000000000000..da848b3d076e5d --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys_dragonfly.go @@ -0,0 +1,71 @@ +// 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 route + +import "unsafe" + +func (typ RIBType) parseable() bool { return true } + +// A RouteMetrics represents route metrics. +type RouteMetrics struct { + PathMTU int // path maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *RouteMessage) Sys() []Sys { + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), + }, + } +} + +// A InterfaceMetrics represents interface metrics. +type InterfaceMetrics struct { + Type int // interface type + MTU int // maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMessage) Sys() []Sys { + return []Sys{ + &InterfaceMetrics{ + Type: int(m.raw[m.extOff]), + MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), + }, + } +} + +func probeRoutingStack() (int, map[int]parseFn) { + var p uintptr + rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4} + ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4} + ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4} + ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4} + ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4} + return int(unsafe.Sizeof(p)), map[int]parseFn{ + sysRTM_ADD: rtm.parseRouteMessage, + sysRTM_DELETE: rtm.parseRouteMessage, + sysRTM_CHANGE: rtm.parseRouteMessage, + sysRTM_GET: rtm.parseRouteMessage, + sysRTM_LOSING: rtm.parseRouteMessage, + sysRTM_REDIRECT: rtm.parseRouteMessage, + sysRTM_MISS: rtm.parseRouteMessage, + sysRTM_LOCK: rtm.parseRouteMessage, + sysRTM_RESOLVE: rtm.parseRouteMessage, + sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage, + sysRTM_DELADDR: ifam.parseInterfaceAddrMessage, + sysRTM_IFINFO: ifm.parseInterfaceMessage, + sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage, + } +} diff --git a/src/vendor/golang.org/x/net/route/sys_freebsd.go b/src/vendor/golang.org/x/net/route/sys_freebsd.go new file mode 100644 index 00000000000000..7b05c1a5a05c11 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys_freebsd.go @@ -0,0 +1,150 @@ +// 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 route + +import ( + "syscall" + "unsafe" +) + +func (typ RIBType) parseable() bool { return true } + +// A RouteMetrics represents route metrics. +type RouteMetrics struct { + PathMTU int // path maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *RouteMessage) Sys() []Sys { + if kernelAlign == 8 { + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), + }, + } + } + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])), + }, + } +} + +// A InterfaceMetrics represents interface metrics. +type InterfaceMetrics struct { + Type int // interface type + MTU int // maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMessage) Sys() []Sys { + return []Sys{ + &InterfaceMetrics{ + Type: int(m.raw[m.extOff]), + MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), + }, + } +} + +func probeRoutingStack() (int, map[int]parseFn) { + var p uintptr + wordSize := int(unsafe.Sizeof(p)) + align := int(unsafe.Sizeof(p)) + // In the case of kern.supported_archs="amd64 i386", we need + // to know the underlying kernel's architecture because the + // alignment for routing facilities are set at the build time + // of the kernel. + conf, _ := syscall.Sysctl("kern.conftxt") + for i, j := 0, 0; j < len(conf); j++ { + if conf[j] != '\n' { + continue + } + s := conf[i:j] + i = j + 1 + if len(s) > len("machine") && s[:len("machine")] == "machine" { + s = s[len("machine"):] + for k := 0; k < len(s); k++ { + if s[k] == ' ' || s[k] == '\t' { + s = s[1:] + } + break + } + if s == "amd64" { + align = 8 + } + break + } + } + var rtm, ifm, ifam, ifmam, ifanm *wireFormat + if align != wordSize { // 386 emulation on amd64 + rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu} + ifm = &wireFormat{extOff: 16} + ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu} + ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu} + ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu} + } else { + rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10} + ifm = &wireFormat{extOff: 16} + ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10} + ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10} + ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10} + } + rel, _ := syscall.SysctlUint32("kern.osreldate") + switch { + case rel < 800000: + if align != wordSize { // 386 emulation on amd64 + ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu + } else { + ifm.bodyOff = sizeofIfMsghdrFreeBSD7 + } + case 800000 <= rel && rel < 900000: + if align != wordSize { // 386 emulation on amd64 + ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu + } else { + ifm.bodyOff = sizeofIfMsghdrFreeBSD8 + } + case 900000 <= rel && rel < 1000000: + if align != wordSize { // 386 emulation on amd64 + ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu + } else { + ifm.bodyOff = sizeofIfMsghdrFreeBSD9 + } + case 1000000 <= rel && rel < 1100000: + if align != wordSize { // 386 emulation on amd64 + ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu + } else { + ifm.bodyOff = sizeofIfMsghdrFreeBSD10 + } + default: + if align != wordSize { // 386 emulation on amd64 + ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu + } else { + ifm.bodyOff = sizeofIfMsghdrFreeBSD11 + } + } + return align, map[int]parseFn{ + sysRTM_ADD: rtm.parseRouteMessage, + sysRTM_DELETE: rtm.parseRouteMessage, + sysRTM_CHANGE: rtm.parseRouteMessage, + sysRTM_GET: rtm.parseRouteMessage, + sysRTM_LOSING: rtm.parseRouteMessage, + sysRTM_REDIRECT: rtm.parseRouteMessage, + sysRTM_MISS: rtm.parseRouteMessage, + sysRTM_LOCK: rtm.parseRouteMessage, + sysRTM_RESOLVE: rtm.parseRouteMessage, + sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage, + sysRTM_DELADDR: ifam.parseInterfaceAddrMessage, + sysRTM_IFINFO: ifm.parseInterfaceMessage, + sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage, + sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage, + } +} diff --git a/src/vendor/golang.org/x/net/route/sys_netbsd.go b/src/vendor/golang.org/x/net/route/sys_netbsd.go new file mode 100644 index 00000000000000..4d8076b518d5b2 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys_netbsd.go @@ -0,0 +1,67 @@ +// 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 route + +func (typ RIBType) parseable() bool { return true } + +// A RouteMetrics represents route metrics. +type RouteMetrics struct { + PathMTU int // path maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *RouteMessage) Sys() []Sys { + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), + }, + } +} + +// A InterfaceMetrics represents interface metrics. +type InterfaceMetrics struct { + Type int // interface type + MTU int // maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMessage) Sys() []Sys { + return []Sys{ + &InterfaceMetrics{ + Type: int(m.raw[m.extOff]), + MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), + }, + } +} + +func probeRoutingStack() (int, map[int]parseFn) { + rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7} + ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7} + ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7} + ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7} + // NetBSD 6 and above kernels require 64-bit aligned access to + // routing facilities. + return 8, map[int]parseFn{ + sysRTM_ADD: rtm.parseRouteMessage, + sysRTM_DELETE: rtm.parseRouteMessage, + sysRTM_CHANGE: rtm.parseRouteMessage, + sysRTM_GET: rtm.parseRouteMessage, + sysRTM_LOSING: rtm.parseRouteMessage, + sysRTM_REDIRECT: rtm.parseRouteMessage, + sysRTM_MISS: rtm.parseRouteMessage, + sysRTM_LOCK: rtm.parseRouteMessage, + sysRTM_RESOLVE: rtm.parseRouteMessage, + sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage, + sysRTM_DELADDR: ifam.parseInterfaceAddrMessage, + sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage, + sysRTM_IFINFO: ifm.parseInterfaceMessage, + } +} diff --git a/src/vendor/golang.org/x/net/route/sys_openbsd.go b/src/vendor/golang.org/x/net/route/sys_openbsd.go new file mode 100644 index 00000000000000..26d043869610ea --- /dev/null +++ b/src/vendor/golang.org/x/net/route/sys_openbsd.go @@ -0,0 +1,72 @@ +// 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 route + +import "unsafe" + +func (typ RIBType) parseable() bool { + switch typ { + case sysNET_RT_STATS, sysNET_RT_TABLE: + return false + default: + return true + } +} + +// A RouteMetrics represents route metrics. +type RouteMetrics struct { + PathMTU int // path maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *RouteMessage) Sys() []Sys { + return []Sys{ + &RouteMetrics{ + PathMTU: int(nativeEndian.Uint32(m.raw[60:64])), + }, + } +} + +// A InterfaceMetrics represents interface metrics. +type InterfaceMetrics struct { + Type int // interface type + MTU int // maximum transmission unit +} + +// SysType implements the SysType method of Sys interface. +func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } + +// Sys implements the Sys method of Message interface. +func (m *InterfaceMessage) Sys() []Sys { + return []Sys{ + &InterfaceMetrics{ + Type: int(m.raw[24]), + MTU: int(nativeEndian.Uint32(m.raw[28:32])), + }, + } +} + +func probeRoutingStack() (int, map[int]parseFn) { + var p uintptr + nooff := &wireFormat{extOff: -1, bodyOff: -1} + return int(unsafe.Sizeof(p)), map[int]parseFn{ + sysRTM_ADD: nooff.parseRouteMessage, + sysRTM_DELETE: nooff.parseRouteMessage, + sysRTM_CHANGE: nooff.parseRouteMessage, + sysRTM_GET: nooff.parseRouteMessage, + sysRTM_LOSING: nooff.parseRouteMessage, + sysRTM_REDIRECT: nooff.parseRouteMessage, + sysRTM_MISS: nooff.parseRouteMessage, + sysRTM_LOCK: nooff.parseRouteMessage, + sysRTM_RESOLVE: nooff.parseRouteMessage, + sysRTM_NEWADDR: nooff.parseInterfaceAddrMessage, + sysRTM_DELADDR: nooff.parseInterfaceAddrMessage, + sysRTM_IFINFO: nooff.parseInterfaceMessage, + sysRTM_IFANNOUNCE: nooff.parseInterfaceAnnounceMessage, + } +} diff --git a/src/vendor/golang.org/x/net/route/syscall.go b/src/vendor/golang.org/x/net/route/syscall.go new file mode 100644 index 00000000000000..d136325a30a258 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/syscall.go @@ -0,0 +1,33 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package route + +import ( + "syscall" + "unsafe" +) + +// TODO: replace with runtime.KeepAlive when available +//go:noescape +func keepAlive(p unsafe.Pointer) + +var zero uintptr + +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + var p unsafe.Pointer + if len(mib) > 0 { + p = unsafe.Pointer(&mib[0]) + } else { + p = unsafe.Pointer(&zero) + } + _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + keepAlive(p) + if errno != 0 { + return error(errno) + } + return nil +} diff --git a/src/vendor/golang.org/x/net/route/syscall.s b/src/vendor/golang.org/x/net/route/syscall.s new file mode 100644 index 00000000000000..fa6297f0aa127d --- /dev/null +++ b/src/vendor/golang.org/x/net/route/syscall.s @@ -0,0 +1,8 @@ +// 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. + +#include "textflag.h" + +TEXT ·keepAlive(SB),NOSPLIT,$0 + RET diff --git a/src/vendor/golang.org/x/net/route/zsys_darwin.go b/src/vendor/golang.org/x/net/route/zsys_darwin.go new file mode 100644 index 00000000000000..265b81cd50e695 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_darwin.go @@ -0,0 +1,93 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_darwin.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x1e + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_STAT = 0x4 + sysNET_RT_TRASH = 0x5 + sysNET_RT_IFLIST2 = 0x6 + sysNET_RT_DUMP2 = 0x7 + sysNET_RT_MAXID = 0xa +) + +const ( + sysCTL_MAXNAME = 0xc + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_MAXID = 0x9 +) + +const ( + sysRTM_VERSION = 0x5 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_OLDADD = 0x9 + sysRTM_OLDDEL = 0xa + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_NEWMADDR = 0xf + sysRTM_DELMADDR = 0x10 + sysRTM_IFINFO2 = 0x12 + sysRTM_NEWMADDR2 = 0x13 + sysRTM_GET2 = 0x14 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_MAX = 0x8 +) + +const ( + sizeofIfMsghdrDarwin15 = 0x70 + sizeofIfaMsghdrDarwin15 = 0x14 + sizeofIfmaMsghdrDarwin15 = 0x10 + sizeofIfMsghdr2Darwin15 = 0xa0 + sizeofIfmaMsghdr2Darwin15 = 0x14 + sizeofIfDataDarwin15 = 0x60 + sizeofIfData64Darwin15 = 0x80 + + sizeofRtMsghdrDarwin15 = 0x5c + sizeofRtMsghdr2Darwin15 = 0x5c + sizeofRtMetricsDarwin15 = 0x38 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/src/vendor/golang.org/x/net/route/zsys_dragonfly.go new file mode 100644 index 00000000000000..dd36dece0f6dbf --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_dragonfly.go @@ -0,0 +1,92 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_dragonfly.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x1c + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_MAXID = 0x4 +) + +const ( + sysCTL_MAXNAME = 0xc + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_P1003_1B = 0x9 + sysCTL_LWKT = 0xa + sysCTL_MAXID = 0xb +) + +const ( + sysRTM_VERSION = 0x6 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_OLDADD = 0x9 + sysRTM_OLDDEL = 0xa + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_NEWMADDR = 0xf + sysRTM_DELMADDR = 0x10 + sysRTM_IFANNOUNCE = 0x11 + sysRTM_IEEE80211 = 0x12 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + sysRTA_MPLS1 = 0x100 + sysRTA_MPLS2 = 0x200 + sysRTA_MPLS3 = 0x400 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_MPLS1 = 0x8 + sysRTAX_MPLS2 = 0x9 + sysRTAX_MPLS3 = 0xa + sysRTAX_MAX = 0xb +) + +const ( + sizeofIfMsghdrDragonFlyBSD4 = 0xb0 + sizeofIfaMsghdrDragonFlyBSD4 = 0x14 + sizeofIfmaMsghdrDragonFlyBSD4 = 0x10 + sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18 + + sizeofRtMsghdrDragonFlyBSD4 = 0x98 + sizeofRtMetricsDragonFlyBSD4 = 0x70 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go new file mode 100644 index 00000000000000..9bac2e3900fbdb --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go @@ -0,0 +1,120 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_freebsd.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x1c + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_IFMALIST = 0x4 + sysNET_RT_IFLISTL = 0x5 +) + +const ( + sysCTL_MAXNAME = 0x18 + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_P1003_1B = 0x9 +) + +const ( + sysRTM_VERSION = 0x5 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_NEWMADDR = 0xf + sysRTM_DELMADDR = 0x10 + sysRTM_IFANNOUNCE = 0x11 + sysRTM_IEEE80211 = 0x12 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_MAX = 0x8 +) + +const ( + sizeofIfMsghdrlFreeBSD10 = 0x68 + sizeofIfaMsghdrFreeBSD10 = 0x14 + sizeofIfaMsghdrlFreeBSD10 = 0x6c + sizeofIfmaMsghdrFreeBSD10 = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 + + sizeofRtMsghdrFreeBSD10 = 0x5c + sizeofRtMetricsFreeBSD10 = 0x38 + + sizeofIfMsghdrFreeBSD7 = 0x60 + sizeofIfMsghdrFreeBSD8 = 0x60 + sizeofIfMsghdrFreeBSD9 = 0x60 + sizeofIfMsghdrFreeBSD10 = 0x64 + sizeofIfMsghdrFreeBSD11 = 0xa8 + + sizeofIfDataFreeBSD7 = 0x50 + sizeofIfDataFreeBSD8 = 0x50 + sizeofIfDataFreeBSD9 = 0x50 + sizeofIfDataFreeBSD10 = 0x54 + sizeofIfDataFreeBSD11 = 0x98 + + // MODIFIED BY HAND FOR 386 EMULATION ON AMD64 + // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT + + sizeofIfMsghdrlFreeBSD10Emu = 0xb0 + sizeofIfaMsghdrFreeBSD10Emu = 0x14 + sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 + sizeofIfmaMsghdrFreeBSD10Emu = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 + + sizeofRtMsghdrFreeBSD10Emu = 0x98 + sizeofRtMetricsFreeBSD10Emu = 0x70 + + sizeofIfMsghdrFreeBSD7Emu = 0xa8 + sizeofIfMsghdrFreeBSD8Emu = 0xa8 + sizeofIfMsghdrFreeBSD9Emu = 0xa8 + sizeofIfMsghdrFreeBSD10Emu = 0xa8 + sizeofIfMsghdrFreeBSD11Emu = 0xa8 + + sizeofIfDataFreeBSD7Emu = 0x98 + sizeofIfDataFreeBSD8Emu = 0x98 + sizeofIfDataFreeBSD9Emu = 0x98 + sizeofIfDataFreeBSD10Emu = 0x98 + sizeofIfDataFreeBSD11Emu = 0x98 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go new file mode 100644 index 00000000000000..b1920d7ac16be8 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go @@ -0,0 +1,117 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_freebsd.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x1c + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_IFMALIST = 0x4 + sysNET_RT_IFLISTL = 0x5 +) + +const ( + sysCTL_MAXNAME = 0x18 + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_P1003_1B = 0x9 +) + +const ( + sysRTM_VERSION = 0x5 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_NEWMADDR = 0xf + sysRTM_DELMADDR = 0x10 + sysRTM_IFANNOUNCE = 0x11 + sysRTM_IEEE80211 = 0x12 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_MAX = 0x8 +) + +const ( + sizeofIfMsghdrlFreeBSD10 = 0xb0 + sizeofIfaMsghdrFreeBSD10 = 0x14 + sizeofIfaMsghdrlFreeBSD10 = 0xb0 + sizeofIfmaMsghdrFreeBSD10 = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 + + sizeofRtMsghdrFreeBSD10 = 0x98 + sizeofRtMetricsFreeBSD10 = 0x70 + + sizeofIfMsghdrFreeBSD7 = 0xa8 + sizeofIfMsghdrFreeBSD8 = 0xa8 + sizeofIfMsghdrFreeBSD9 = 0xa8 + sizeofIfMsghdrFreeBSD10 = 0xa8 + sizeofIfMsghdrFreeBSD11 = 0xa8 + + sizeofIfDataFreeBSD7 = 0x98 + sizeofIfDataFreeBSD8 = 0x98 + sizeofIfDataFreeBSD9 = 0x98 + sizeofIfDataFreeBSD10 = 0x98 + sizeofIfDataFreeBSD11 = 0x98 + + sizeofIfMsghdrlFreeBSD10Emu = 0xb0 + sizeofIfaMsghdrFreeBSD10Emu = 0x14 + sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 + sizeofIfmaMsghdrFreeBSD10Emu = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 + + sizeofRtMsghdrFreeBSD10Emu = 0x98 + sizeofRtMetricsFreeBSD10Emu = 0x70 + + sizeofIfMsghdrFreeBSD7Emu = 0xa8 + sizeofIfMsghdrFreeBSD8Emu = 0xa8 + sizeofIfMsghdrFreeBSD9Emu = 0xa8 + sizeofIfMsghdrFreeBSD10Emu = 0xa8 + sizeofIfMsghdrFreeBSD11Emu = 0xa8 + + sizeofIfDataFreeBSD7Emu = 0x98 + sizeofIfDataFreeBSD8Emu = 0x98 + sizeofIfDataFreeBSD9Emu = 0x98 + sizeofIfDataFreeBSD10Emu = 0x98 + sizeofIfDataFreeBSD11Emu = 0x98 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go new file mode 100644 index 00000000000000..a034d6fcbf215c --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go @@ -0,0 +1,117 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_freebsd.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x1c + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_IFMALIST = 0x4 + sysNET_RT_IFLISTL = 0x5 +) + +const ( + sysCTL_MAXNAME = 0x18 + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_P1003_1B = 0x9 +) + +const ( + sysRTM_VERSION = 0x5 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_NEWMADDR = 0xf + sysRTM_DELMADDR = 0x10 + sysRTM_IFANNOUNCE = 0x11 + sysRTM_IEEE80211 = 0x12 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_MAX = 0x8 +) + +const ( + sizeofIfMsghdrlFreeBSD10 = 0x68 + sizeofIfaMsghdrFreeBSD10 = 0x14 + sizeofIfaMsghdrlFreeBSD10 = 0x6c + sizeofIfmaMsghdrFreeBSD10 = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 + + sizeofRtMsghdrFreeBSD10 = 0x5c + sizeofRtMetricsFreeBSD10 = 0x38 + + sizeofIfMsghdrFreeBSD7 = 0x70 + sizeofIfMsghdrFreeBSD8 = 0x70 + sizeofIfMsghdrFreeBSD9 = 0x70 + sizeofIfMsghdrFreeBSD10 = 0x70 + sizeofIfMsghdrFreeBSD11 = 0xa8 + + sizeofIfDataFreeBSD7 = 0x60 + sizeofIfDataFreeBSD8 = 0x60 + sizeofIfDataFreeBSD9 = 0x60 + sizeofIfDataFreeBSD10 = 0x60 + sizeofIfDataFreeBSD11 = 0x98 + + sizeofIfMsghdrlFreeBSD10Emu = 0x68 + sizeofIfaMsghdrFreeBSD10Emu = 0x14 + sizeofIfaMsghdrlFreeBSD10Emu = 0x6c + sizeofIfmaMsghdrFreeBSD10Emu = 0x10 + sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 + + sizeofRtMsghdrFreeBSD10Emu = 0x5c + sizeofRtMetricsFreeBSD10Emu = 0x38 + + sizeofIfMsghdrFreeBSD7Emu = 0x70 + sizeofIfMsghdrFreeBSD8Emu = 0x70 + sizeofIfMsghdrFreeBSD9Emu = 0x70 + sizeofIfMsghdrFreeBSD10Emu = 0x70 + sizeofIfMsghdrFreeBSD11Emu = 0xa8 + + sizeofIfDataFreeBSD7Emu = 0x60 + sizeofIfDataFreeBSD8Emu = 0x60 + sizeofIfDataFreeBSD9Emu = 0x60 + sizeofIfDataFreeBSD10Emu = 0x60 + sizeofIfDataFreeBSD11Emu = 0x98 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/src/vendor/golang.org/x/net/route/zsys_netbsd.go new file mode 100644 index 00000000000000..aa4aad1613e22f --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_netbsd.go @@ -0,0 +1,91 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_netbsd.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x22 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x18 + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x5 + sysNET_RT_MAXID = 0x6 +) + +const ( + sysCTL_MAXNAME = 0xc + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_VFS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_USER = 0x8 + sysCTL_DDB = 0x9 + sysCTL_PROC = 0xa + sysCTL_VENDOR = 0xb + sysCTL_EMUL = 0xc + sysCTL_SECURITY = 0xd + sysCTL_MAXID = 0xe +) + +const ( + sysRTM_VERSION = 0x4 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_OLDADD = 0x9 + sysRTM_OLDDEL = 0xa + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFANNOUNCE = 0x10 + sysRTM_IEEE80211 = 0x11 + sysRTM_SETGATE = 0x12 + sysRTM_LLINFO_UPD = 0x13 + sysRTM_IFINFO = 0x14 + sysRTM_CHGADDR = 0x15 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + sysRTA_TAG = 0x100 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_TAG = 0x8 + sysRTAX_MAX = 0x9 +) + +const ( + sizeofIfMsghdrNetBSD7 = 0x98 + sizeofIfaMsghdrNetBSD7 = 0x18 + sizeofIfAnnouncemsghdrNetBSD7 = 0x18 + + sizeofRtMsghdrNetBSD7 = 0x78 + sizeofRtMetricsNetBSD7 = 0x50 +) diff --git a/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/src/vendor/golang.org/x/net/route/zsys_openbsd.go new file mode 100644 index 00000000000000..4fadc4e8fa1e54 --- /dev/null +++ b/src/vendor/golang.org/x/net/route/zsys_openbsd.go @@ -0,0 +1,80 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs defs_openbsd.go + +package route + +const ( + sysAF_UNSPEC = 0x0 + sysAF_INET = 0x2 + sysAF_ROUTE = 0x11 + sysAF_LINK = 0x12 + sysAF_INET6 = 0x18 + + sysNET_RT_DUMP = 0x1 + sysNET_RT_FLAGS = 0x2 + sysNET_RT_IFLIST = 0x3 + sysNET_RT_STATS = 0x4 + sysNET_RT_TABLE = 0x5 + sysNET_RT_IFNAMES = 0x6 + sysNET_RT_MAXID = 0x7 +) + +const ( + sysCTL_MAXNAME = 0xc + + sysCTL_UNSPEC = 0x0 + sysCTL_KERN = 0x1 + sysCTL_VM = 0x2 + sysCTL_FS = 0x3 + sysCTL_NET = 0x4 + sysCTL_DEBUG = 0x5 + sysCTL_HW = 0x6 + sysCTL_MACHDEP = 0x7 + sysCTL_DDB = 0x9 + sysCTL_VFS = 0xa + sysCTL_MAXID = 0xb +) + +const ( + sysRTM_VERSION = 0x5 + + sysRTM_ADD = 0x1 + sysRTM_DELETE = 0x2 + sysRTM_CHANGE = 0x3 + sysRTM_GET = 0x4 + sysRTM_LOSING = 0x5 + sysRTM_REDIRECT = 0x6 + sysRTM_MISS = 0x7 + sysRTM_LOCK = 0x8 + sysRTM_RESOLVE = 0xb + sysRTM_NEWADDR = 0xc + sysRTM_DELADDR = 0xd + sysRTM_IFINFO = 0xe + sysRTM_IFANNOUNCE = 0xf + sysRTM_DESYNC = 0x10 + + sysRTA_DST = 0x1 + sysRTA_GATEWAY = 0x2 + sysRTA_NETMASK = 0x4 + sysRTA_GENMASK = 0x8 + sysRTA_IFP = 0x10 + sysRTA_IFA = 0x20 + sysRTA_AUTHOR = 0x40 + sysRTA_BRD = 0x80 + sysRTA_SRC = 0x100 + sysRTA_SRCMASK = 0x200 + sysRTA_LABEL = 0x400 + + sysRTAX_DST = 0x0 + sysRTAX_GATEWAY = 0x1 + sysRTAX_NETMASK = 0x2 + sysRTAX_GENMASK = 0x3 + sysRTAX_IFP = 0x4 + sysRTAX_IFA = 0x5 + sysRTAX_AUTHOR = 0x6 + sysRTAX_BRD = 0x7 + sysRTAX_SRC = 0x8 + sysRTAX_SRCMASK = 0x9 + sysRTAX_LABEL = 0xa + sysRTAX_MAX = 0xb +) From 0bc14f57ec7e5518af711a64103ca2ac72f19a6e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 14 May 2016 17:33:23 -0700 Subject: [PATCH 103/267] strings: fix Contains on amd64 The 17-31 byte code is broken. Disabled it. Added a bunch of tests to at least cover the cases in indexShortStr. I'll channel Brad and wonder why this CL ever got in without any tests. Fixes #15679 Change-Id: I84a7b283a74107db865b9586c955dcf5f2d60161 Reviewed-on: https://go-review.googlesource.com/23106 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/asm_amd64.s | 1 + src/strings/strings_amd64.go | 2 +- src/strings/strings_test.go | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 6cd31f951bda74..d6e54941805b4a 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -1800,6 +1800,7 @@ loop16: CMPQ DI,DX JB loop16 JMP fail +//TODO: the code below is wrong. Fix it. See #15679. _17_to_31: LEAQ 1(DI)(DX*1), DX SUBQ AX, DX diff --git a/src/strings/strings_amd64.go b/src/strings/strings_amd64.go index 55bf2d2f6fc77a..91b29ce358fa6d 100644 --- a/src/strings/strings_amd64.go +++ b/src/strings/strings_amd64.go @@ -7,7 +7,7 @@ package strings // indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s. // indexShortStr requires 2 <= len(c) <= shortStringLen func indexShortStr(s, c string) int // ../runtime/asm_$GOARCH.s -const shortStringLen = 31 +const shortStringLen = 16 // TODO: restore to 31 when #15679 is fixed // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. func Index(s, sep string) int { diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index d92dfcc8742b27..6bd6fb5443d31f 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -1036,6 +1036,70 @@ var ContainsTests = []struct { {"abc", "bcd", false}, {"abc", "", true}, {"", "a", false}, + + // cases to cover code in runtime/asm_amd64.s:indexShortStr + // 2-byte needle + {"xxxxxx", "01", false}, + {"01xxxx", "01", true}, + {"xx01xx", "01", true}, + {"xxxx01", "01", true}, + {"01xxxxx"[1:], "01", false}, + {"xxxxx01"[:6], "01", false}, + // 3-byte needle + {"xxxxxxx", "012", false}, + {"012xxxx", "012", true}, + {"xx012xx", "012", true}, + {"xxxx012", "012", true}, + {"012xxxxx"[1:], "012", false}, + {"xxxxx012"[:7], "012", false}, + // 4-byte needle + {"xxxxxxxx", "0123", false}, + {"0123xxxx", "0123", true}, + {"xx0123xx", "0123", true}, + {"xxxx0123", "0123", true}, + {"0123xxxxx"[1:], "0123", false}, + {"xxxxx0123"[:8], "0123", false}, + // 5-7-byte needle + {"xxxxxxxxx", "01234", false}, + {"01234xxxx", "01234", true}, + {"xx01234xx", "01234", true}, + {"xxxx01234", "01234", true}, + {"01234xxxxx"[1:], "01234", false}, + {"xxxxx01234"[:9], "01234", false}, + // 8-byte needle + {"xxxxxxxxxxxx", "01234567", false}, + {"01234567xxxx", "01234567", true}, + {"xx01234567xx", "01234567", true}, + {"xxxx01234567", "01234567", true}, + {"01234567xxxxx"[1:], "01234567", false}, + {"xxxxx01234567"[:12], "01234567", false}, + // 9-15-byte needle + {"xxxxxxxxxxxxx", "012345678", false}, + {"012345678xxxx", "012345678", true}, + {"xx012345678xx", "012345678", true}, + {"xxxx012345678", "012345678", true}, + {"012345678xxxxx"[1:], "012345678", false}, + {"xxxxx012345678"[:13], "012345678", false}, + // 16-byte needle + {"xxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEF", false}, + {"0123456789ABCDEFxxxx", "0123456789ABCDEF", true}, + {"xx0123456789ABCDEFxx", "0123456789ABCDEF", true}, + {"xxxx0123456789ABCDEF", "0123456789ABCDEF", true}, + {"0123456789ABCDEFxxxxx"[1:], "0123456789ABCDEF", false}, + {"xxxxx0123456789ABCDEF"[:20], "0123456789ABCDEF", false}, + // 17-31-byte needle + {"xxxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEFG", false}, + {"0123456789ABCDEFGxxxx", "0123456789ABCDEFG", true}, + {"xx0123456789ABCDEFGxx", "0123456789ABCDEFG", true}, + {"xxxx0123456789ABCDEFG", "0123456789ABCDEFG", true}, + {"0123456789ABCDEFGxxxxx"[1:], "0123456789ABCDEFG", false}, + {"xxxxx0123456789ABCDEFG"[:21], "0123456789ABCDEFG", false}, + + // partial match cases + {"xx01x", "012", false}, // 3 + {"xx0123x", "01234", false}, // 5-7 + {"xx01234567x", "012345678", false}, // 9-15 + {"xx0123456789ABCDEFx", "0123456789ABCDEFG", false}, // 17-31, issue 15679 } func TestContains(t *testing.T) { From b4bf0663fa3334d053981f222eed5015a0a1b8df Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 23 Apr 2016 22:36:41 +0900 Subject: [PATCH 104/267] net: golang.org/x/net/route plumbing This change makes use of new routing message APIs for BSD variants to support FreeBSD 11 and newer versions of other BSDs. Fixes #7849. Fixes #14724. Change-Id: I56c7886d6622cdeddd7cc29c8a8062dcc06216d5 Reviewed-on: https://go-review.googlesource.com/22451 Reviewed-by: Ian Lance Taylor Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot --- src/go/build/deps_test.go | 7 +- src/net/interface_bsd.go | 167 ++++++------------ ...rface_dragonfly.go => interface_bsdvar.go} | 16 ++ src/net/interface_darwin.go | 67 +++---- src/net/interface_freebsd.go | 72 ++++---- src/net/interface_netbsd.go | 12 -- src/net/interface_openbsd.go | 12 -- src/net/interface_test.go | 21 --- 8 files changed, 141 insertions(+), 233 deletions(-) rename src/net/{interface_dragonfly.go => interface_bsdvar.go} (54%) delete mode 100644 src/net/interface_netbsd.go delete mode 100644 src/net/interface_openbsd.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index d0d4fbba162967..958e410dd95120 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -292,10 +292,13 @@ var pkgDeps = map[string][]string{ // Basic networking. // Because net must be used by any package that wants to // do networking portably, it must have a small dependency set: just L0+basic os. - "net": {"L0", "CGO", + "net": { + "L0", "CGO", "context", "math/rand", "os", "sort", "syscall", "time", "internal/nettrace", - "internal/syscall/windows", "internal/singleflight", "internal/race"}, + "internal/syscall/windows", "internal/singleflight", "internal/race", + "golang.org/x/net/route", + }, // NET enables use of basic network-related packages. "NET": { diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 17c6dd3dcd69df..1ca2f36e772790 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -7,74 +7,58 @@ package net import ( - "os" "syscall" - "unsafe" + + "golang.org/x/net/route" ) // If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otherwise it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { - tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) - if err != nil { - return nil, os.NewSyscallError("routerib", err) - } - msgs, err := syscall.ParseRoutingMessage(tab) + msgs, err := interfaceMessages(ifindex) if err != nil { - return nil, os.NewSyscallError("parseroutingmessage", err) + return nil, err } return parseInterfaceTable(ifindex, msgs) } -func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) { - var ift []Interface -loop: +func parseInterfaceTable(ifindex int, msgs []route.Message) ([]Interface, error) { + n := len(msgs) + if ifindex != 0 { + n = 1 + } + ift := make([]Interface, n) + n = 0 for _, m := range msgs { switch m := m.(type) { - case *syscall.InterfaceMessage: - if ifindex == 0 || ifindex == int(m.Header.Index) { - ifi, err := newLink(m) - if err != nil { - return nil, err - } - ift = append(ift, *ifi) - if ifindex == int(m.Header.Index) { - break loop + case *route.InterfaceMessage: + if ifindex != 0 && ifindex != m.Index { + continue + } + ift[n].Index = m.Index + ift[n].Name = m.Name + ift[n].Flags = linkFlags(m.Flags) + if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 { + ift[n].HardwareAddr = make([]byte, len(sa.Addr)) + copy(ift[n].HardwareAddr, sa.Addr) + } + for _, sys := range m.Sys() { + if imx, ok := sys.(*route.InterfaceMetrics); ok { + ift[n].MTU = imx.MTU + break } } + n++ + if ifindex == m.Index { + return ift[:n], nil + } } } - return ift, nil -} - -func newLink(m *syscall.InterfaceMessage) (*Interface, error) { - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, os.NewSyscallError("parseroutingsockaddr", err) - } - ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)} - sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink) - if sa != nil { - // NOTE: SockaddrDatalink.Data is minimum work area, - // can be larger. - m.Data = m.Data[unsafe.Offsetof(sa.Data):] - var name [syscall.IFNAMSIZ]byte - for i := 0; i < int(sa.Nlen); i++ { - name[i] = m.Data[i] - } - ifi.Name = string(name[:sa.Nlen]) - ifi.MTU = int(m.Header.Data.Mtu) - addr := make([]byte, sa.Alen) - for i := 0; i < int(sa.Alen); i++ { - addr[i] = m.Data[int(sa.Nlen)+i] - } - ifi.HardwareAddr = addr[:sa.Alen] - } - return ifi, nil + return ift[:n], nil } -func linkFlags(rawFlags int32) Flags { +func linkFlags(rawFlags int) Flags { var f Flags if rawFlags&syscall.IFF_UP != 0 { f |= FlagUp @@ -102,74 +86,37 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { if ifi != nil { index = ifi.Index } - tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index) - if err != nil { - return nil, os.NewSyscallError("routerib", err) - } - msgs, err := syscall.ParseRoutingMessage(tab) + msgs, err := interfaceMessages(index) if err != nil { - return nil, os.NewSyscallError("parseroutingmessage", err) + return nil, err } - var ift []Interface - if index == 0 { - ift, err = parseInterfaceTable(index, msgs) - if err != nil { - return nil, err - } - } - var ifat []Addr + ifat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *syscall.InterfaceAddrMessage: - if index == 0 || index == int(m.Header.Index) { - if index == 0 { - var err error - ifi, err = interfaceByIndex(ift, int(m.Header.Index)) - if err != nil { - return nil, err - } - } - ifa, err := newAddr(ifi, m) - if err != nil { - return nil, err - } - if ifa != nil { - ifat = append(ifat, ifa) - } + case *route.InterfaceAddrMessage: + if index != 0 && index != m.Index { + continue + } + var mask IPMask + switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) { + case *route.Inet4Addr: + mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) + case *route.Inet6Addr: + mask = make(IPMask, IPv6len) + copy(mask, sa.IP[:]) + } + var ip IP + switch sa := m.Addrs[syscall.RTAX_IFA].(type) { + case *route.Inet4Addr: + ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) + case *route.Inet6Addr: + ip = make(IP, IPv6len) + copy(ip, sa.IP[:]) + } + if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr + ifat = append(ifat, &IPNet{IP: ip, Mask: mask}) } } } return ifat, nil } - -func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) { - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, os.NewSyscallError("parseroutingsockaddr", err) - } - ifa := &IPNet{} - switch sa := sas[syscall.RTAX_NETMASK].(type) { - case *syscall.SockaddrInet4: - ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - case *syscall.SockaddrInet6: - ifa.Mask = make(IPMask, IPv6len) - copy(ifa.Mask, sa.Addr[:]) - } - switch sa := sas[syscall.RTAX_IFA].(type) { - case *syscall.SockaddrInet4: - ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - case *syscall.SockaddrInet6: - ifa.IP = make(IP, IPv6len) - copy(ifa.IP, sa.Addr[:]) - // 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() { - ifa.IP[2], ifa.IP[3] = 0, 0 - } - } - if ifa.IP == nil || ifa.Mask == nil { - return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD - } - return ifa, nil -} diff --git a/src/net/interface_dragonfly.go b/src/net/interface_bsdvar.go similarity index 54% rename from src/net/interface_dragonfly.go rename to src/net/interface_bsdvar.go index cb7a34ab166004..a809b5f5ce49e6 100644 --- a/src/net/interface_dragonfly.go +++ b/src/net/interface_bsdvar.go @@ -2,8 +2,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build dragonfly netbsd openbsd + package net +import ( + "syscall" + + "golang.org/x/net/route" +) + +func interfaceMessages(ifindex int) ([]route.Message, error) { + rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) + if err != nil { + return nil, err + } + return route.ParseRIB(syscall.NET_RT_IFLIST, rib) +} + // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go index 72fb9443c07d49..bb4fd73a987670 100644 --- a/src/net/interface_darwin.go +++ b/src/net/interface_darwin.go @@ -5,58 +5,49 @@ package net import ( - "os" "syscall" + + "golang.org/x/net/route" ) +func interfaceMessages(ifindex int) ([]route.Message, error) { + rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) + if err != nil { + return nil, err + } + return route.ParseRIB(syscall.NET_RT_IFLIST, rib) +} + // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index) + rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index) if err != nil { - return nil, os.NewSyscallError("routerib", err) + return nil, err } - msgs, err := syscall.ParseRoutingMessage(tab) + msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib) if err != nil { - return nil, os.NewSyscallError("parseroutingmessage", err) + return nil, err } - var ifmat []Addr + ifmat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *syscall.InterfaceMulticastAddrMessage: - if ifi.Index == int(m.Header.Index) { - ifma, err := newMulticastAddr(ifi, m) - if err != nil { - return nil, err - } - if ifma != nil { - ifmat = append(ifmat, ifma) - } + case *route.InterfaceMulticastAddrMessage: + if ifi.Index != m.Index { + continue + } + var ip IP + switch sa := m.Addrs[syscall.RTAX_IFA].(type) { + case *route.Inet4Addr: + ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) + case *route.Inet6Addr: + ip = make(IP, IPv6len) + copy(ip, sa.IP[:]) + } + if ip != nil { + ifmat = append(ifmat, &IPAddr{IP: ip}) } } } return ifmat, nil } - -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, os.NewSyscallError("parseroutingsockaddr", err) - } - switch sa := sas[syscall.RTAX_IFA].(type) { - case *syscall.SockaddrInet4: - return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil - case *syscall.SockaddrInet6: - ifma := IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // 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() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - return &ifma, nil - default: - return nil, nil - } -} diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go index bddee8bacb75f2..45badd64954a17 100644 --- a/src/net/interface_freebsd.go +++ b/src/net/interface_freebsd.go @@ -5,58 +5,54 @@ package net import ( - "os" "syscall" + + "golang.org/x/net/route" ) +func interfaceMessages(ifindex int) ([]route.Message, error) { + typ := route.RIBType(syscall.NET_RT_IFLISTL) + rib, err := route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex) + if err != nil { + typ = route.RIBType(syscall.NET_RT_IFLIST) + rib, err = route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex) + } + if err != nil { + return nil, err + } + return route.ParseRIB(typ, rib) +} + // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index) + rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index) if err != nil { - return nil, os.NewSyscallError("routerib", err) + return nil, err } - msgs, err := syscall.ParseRoutingMessage(tab) + msgs, err := route.ParseRIB(syscall.NET_RT_IFMALIST, rib) if err != nil { - return nil, os.NewSyscallError("parseroutingmessage", err) + return nil, err } - var ifmat []Addr + ifmat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *syscall.InterfaceMulticastAddrMessage: - if ifi.Index == int(m.Header.Index) { - ifma, err := newMulticastAddr(ifi, m) - if err != nil { - return nil, err - } - if ifma != nil { - ifmat = append(ifmat, ifma) - } + case *route.InterfaceMulticastAddrMessage: + if ifi.Index != m.Index { + continue + } + var ip IP + switch sa := m.Addrs[syscall.RTAX_IFA].(type) { + case *route.Inet4Addr: + ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) + case *route.Inet6Addr: + ip = make(IP, IPv6len) + copy(ip, sa.IP[:]) + } + if ip != nil { + ifmat = append(ifmat, &IPAddr{IP: ip}) } } } return ifmat, nil } - -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, os.NewSyscallError("parseroutingsockaddr", err) - } - switch sa := sas[syscall.RTAX_IFA].(type) { - case *syscall.SockaddrInet4: - return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil - case *syscall.SockaddrInet6: - ifma := IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // 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() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - return &ifma, nil - default: - return nil, nil - } -} diff --git a/src/net/interface_netbsd.go b/src/net/interface_netbsd.go deleted file mode 100644 index cb7a34ab166004..00000000000000 --- a/src/net/interface_netbsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -// interfaceMulticastAddrTable returns addresses for a specific -// interface. -func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - // TODO(mikio): Implement this like other platforms. - return nil, nil -} diff --git a/src/net/interface_openbsd.go b/src/net/interface_openbsd.go deleted file mode 100644 index cb7a34ab166004..00000000000000 --- a/src/net/interface_openbsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -// interfaceMulticastAddrTable returns addresses for a specific -// interface. -func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - // TODO(mikio): Implement this like other platforms. - return nil, nil -} diff --git a/src/net/interface_test.go b/src/net/interface_test.go index 2603311d24ba29..4c695b902a226c 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -6,7 +6,6 @@ package net import ( "fmt" - "internal/testenv" "reflect" "runtime" "testing" @@ -50,11 +49,6 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string { } func TestInterfaces(t *testing.T) { - if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { - // 100% flaky on FreeBSD 11-CURRENT and above. - testenv.SkipFlaky(t, 7849) - } - ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -79,11 +73,6 @@ func TestInterfaces(t *testing.T) { } func TestInterfaceAddrs(t *testing.T) { - if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { - // 100% flaky on FreeBSD 11-CURRENT and above. - testenv.SkipFlaky(t, 7849) - } - ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -103,11 +92,6 @@ func TestInterfaceAddrs(t *testing.T) { } func TestInterfaceUnicastAddrs(t *testing.T) { - if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { - // 100% flaky on FreeBSD 11-CURRENT and above. - testenv.SkipFlaky(t, 7849) - } - ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -135,11 +119,6 @@ func TestInterfaceUnicastAddrs(t *testing.T) { } func TestInterfaceMulticastAddrs(t *testing.T) { - if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { - // 100% flaky on FreeBSD 11-CURRENT and above. - testenv.SkipFlaky(t, 7849) - } - ift, err := Interfaces() if err != nil { t.Fatal(err) From 6cc6ef82ea1ea5c904bb44c14bb6f4eb33937bb1 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sun, 15 May 2016 20:12:34 +0200 Subject: [PATCH 105/267] mime: fix mime type file name on Plan 9 There was a typo introduced in the initial implementation of the Plan 9 support of the mime package. On Plan 9, the mime type file name should be /sys/lib/mimetype instead of /sys/lib/mimetypes. Change-Id: If0f0a9b6f3fbfa8dde551f790e83bdd05e8f0acb Reviewed-on: https://go-review.googlesource.com/23087 Run-TryBot: Minux Ma Reviewed-by: Minux Ma TryBot-Result: Gobot Gobot --- src/mime/type_plan9.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mime/type_plan9.go b/src/mime/type_plan9.go index c3ba186e7c6b48..14ff9734051863 100644 --- a/src/mime/type_plan9.go +++ b/src/mime/type_plan9.go @@ -21,7 +21,7 @@ func initMimePlan9() { } var typeFiles = []string{ - "/sys/lib/mimetypes", + "/sys/lib/mimetype", } func initMimeForTests() map[string]string { From 6d66819587b9de3d7602721830884fd92a0f7090 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 23 Apr 2016 22:36:41 +0900 Subject: [PATCH 106/267] syscall: deprecate routing message APIs for BSD variants Also removes unnecessary test cases for avoiding unexpected failures on newer operating systems. Updates #14724. Change-Id: I2291585d951fb70383da68293a6ac1ff3524c7f7 Reviewed-on: https://go-review.googlesource.com/22452 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/syscall/route_bsd.go | 14 ++ src/syscall/route_bsd_test.go | 260 ------------------------------- src/syscall/route_darwin.go | 2 + src/syscall/route_dragonfly.go | 4 + src/syscall/route_freebsd.go | 4 + src/syscall/route_ifma_test.go | 74 --------- src/syscall/route_netbsd.go | 2 + src/syscall/route_noifma_test.go | 63 -------- src/syscall/route_openbsd.go | 2 + 9 files changed, 28 insertions(+), 397 deletions(-) delete mode 100644 src/syscall/route_bsd_test.go delete mode 100644 src/syscall/route_ifma_test.go delete mode 100644 src/syscall/route_noifma_test.go diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go index fe8259b221e27f..b364eeaba5dc05 100644 --- a/src/syscall/route_bsd.go +++ b/src/syscall/route_bsd.go @@ -176,6 +176,8 @@ func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) { // RouteRIB returns routing information base, as known as RIB, // which consists of network facility information, states and // parameters. +// +// Deprecated: Use golang.org/x/net/route instead. func RouteRIB(facility, param int) ([]byte, error) { mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)} // Find size. @@ -194,6 +196,8 @@ func RouteRIB(facility, param int) ([]byte, error) { } // RoutingMessage represents a routing message. +// +// Deprecated: Use golang.org/x/net/route instead. type RoutingMessage interface { sockaddr() ([]Sockaddr, error) } @@ -208,6 +212,8 @@ type anyMessage struct { // RouteMessage represents a routing message containing routing // entries. +// +// Deprecated: Use golang.org/x/net/route instead. type RouteMessage struct { Header RtMsghdr Data []byte @@ -252,6 +258,8 @@ func (m *RouteMessage) sockaddr() ([]Sockaddr, error) { // InterfaceMessage represents a routing message containing // network interface entries. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceMessage struct { Header IfMsghdr Data []byte @@ -272,6 +280,8 @@ func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) { // InterfaceAddrMessage represents a routing message containing // network interface address entries. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceAddrMessage struct { Header IfaMsghdr Data []byte @@ -316,6 +326,8 @@ func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { // ParseRoutingMessage parses b as routing messages and returns the // slice containing the RoutingMessage interfaces. +// +// Deprecated: Use golang.org/x/net/route instead. func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { nmsgs, nskips := 0, 0 for len(b) >= anyMessageLen { @@ -341,6 +353,8 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { // ParseRoutingSockaddr parses msg's payload as raw sockaddrs and // returns the slice containing the Sockaddr interfaces. +// +// Deprecated: Use golang.org/x/net/route instead. func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { sas, err := msg.sockaddr() if err != nil { diff --git a/src/syscall/route_bsd_test.go b/src/syscall/route_bsd_test.go deleted file mode 100644 index 74d11f9f0a578e..00000000000000 --- a/src/syscall/route_bsd_test.go +++ /dev/null @@ -1,260 +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. - -// +build darwin dragonfly freebsd netbsd openbsd - -package syscall_test - -import ( - "fmt" - "net" - "os" - "syscall" - "testing" - "time" -) - -func TestRouteRIB(t *testing.T) { - for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { - for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { - var err error - var b []byte - // The VM allocator wrapper functions can - // return ENOMEM easily. - for i := 0; i < 3; i++ { - b, err = syscall.RouteRIB(facility, param) - if err != nil { - time.Sleep(5 * time.Millisecond) - continue - } - break - } - if err != nil { - t.Error(facility, param, err) - continue - } - msgs, err := syscall.ParseRoutingMessage(b) - if err != nil { - t.Error(facility, param, err) - continue - } - var ipv4loopback, ipv6loopback bool - for _, m := range msgs { - flags, err := parseRoutingMessageHeader(m) - if err != nil { - t.Error(err) - continue - } - sas, err := parseRoutingSockaddrs(m) - if err != nil { - t.Error(err) - continue - } - if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 { - sa := sas[syscall.RTAX_DST] - if sa == nil { - sa = sas[syscall.RTAX_IFA] - } - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - if net.IP(sa.Addr[:]).IsLoopback() { - ipv4loopback = true - } - case *syscall.SockaddrInet6: - if net.IP(sa.Addr[:]).IsLoopback() { - ipv6loopback = true - } - } - } - t.Log(facility, param, flags, sockaddrs(sas)) - } - if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback { - t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs)) - continue - } - } - } -} - -func TestRouteMonitor(t *testing.T) { - if testing.Short() || os.Getuid() != 0 { - t.Skip("must be root") - } - - s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) - if err != nil { - t.Fatal(err) - } - defer syscall.Close(s) - - tmo := time.After(30 * time.Second) - go func() { - b := make([]byte, os.Getpagesize()) - for { - n, err := syscall.Read(s, b) - if err != nil { - return - } - msgs, err := syscall.ParseRoutingMessage(b[:n]) - if err != nil { - t.Error(err) - return - } - for _, m := range msgs { - flags, err := parseRoutingMessageHeader(m) - if err != nil { - t.Error(err) - continue - } - sas, err := parseRoutingSockaddrs(m) - if err != nil { - t.Error(err) - continue - } - t.Log(flags, sockaddrs(sas)) - } - } - }() - <-tmo -} - -var parseInterfaceMessageTests = []*syscall.InterfaceMessage{ - // with link-layer address - { - Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP}, - Data: []uint8{ - 0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0, - 0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd, - 0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }, - }, - // without link-layer address - { - Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP}, - Data: []uint8{ - 0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0, - 0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0, - }, - }, - // no data - { - Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP}, - Data: []uint8{ - 0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0, - }, - }, -} - -func TestParseInterfaceMessage(t *testing.T) { - for i, tt := range parseInterfaceMessageTests { - if _, err := syscall.ParseRoutingSockaddr(tt); err != nil { - t.Errorf("#%d: %v", i, err) - } - } -} - -type addrFamily byte - -func (f addrFamily) String() string { - switch f { - case syscall.AF_UNSPEC: - return "unspec" - case syscall.AF_LINK: - return "link" - case syscall.AF_INET: - return "inet4" - case syscall.AF_INET6: - return "inet6" - default: - return fmt.Sprintf("unknown %d", f) - } -} - -type addrFlags uint32 - -var addrFlagNames = [...]string{ - "dst", - "gateway", - "netmask", - "genmask", - "ifp", - "ifa", - "author", - "brd", - "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd - "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd - "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd -} - -func (f addrFlags) String() string { - var s string - for i, name := range addrFlagNames { - if f&(1<" - } - return s -} - -type sockaddrs []syscall.Sockaddr - -func (sas sockaddrs) String() string { - var s string - for _, sa := range sas { - if sa == nil { - continue - } - if len(s) > 0 { - s += " " - } - switch sa := sa.(type) { - case *syscall.SockaddrDatalink: - s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen) - case *syscall.SockaddrInet4: - s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4()) - case *syscall.SockaddrInet6: - s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16()) - } - } - if s == "" { - return "" - } - return s -} - -func (sas sockaddrs) match(flags addrFlags) error { - var f addrFlags - family := syscall.AF_UNSPEC - for i := range sas { - if sas[i] != nil { - f |= 1 << uint(i) - } - switch sas[i].(type) { - case *syscall.SockaddrInet4: - if family == syscall.AF_UNSPEC { - family = syscall.AF_INET - } - if family != syscall.AF_INET { - return fmt.Errorf("got %v; want %v", sockaddrs(sas), family) - } - case *syscall.SockaddrInet6: - if family == syscall.AF_UNSPEC { - family = syscall.AF_INET6 - } - if family != syscall.AF_INET6 { - return fmt.Errorf("got %v; want %v", sockaddrs(sas), family) - } - } - } - if f != flags { - return fmt.Errorf("got %v; want %v", f, flags) - } - return nil -} diff --git a/src/syscall/route_darwin.go b/src/syscall/route_darwin.go index bb353b20111707..b0636ed07ceef0 100644 --- a/src/syscall/route_darwin.go +++ b/src/syscall/route_darwin.go @@ -26,6 +26,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { // InterfaceMulticastAddrMessage represents a routing message // containing network interface address entries. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceMulticastAddrMessage struct { Header IfmaMsghdr2 Data []byte diff --git a/src/syscall/route_dragonfly.go b/src/syscall/route_dragonfly.go index 78daf94deb4c41..b562400be8bdb7 100644 --- a/src/syscall/route_dragonfly.go +++ b/src/syscall/route_dragonfly.go @@ -31,6 +31,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { // InterfaceAnnounceMessage represents a routing message containing // network interface arrival and departure information. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } @@ -39,6 +41,8 @@ func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, // InterfaceMulticastAddrMessage represents a routing message // containing network interface address entries. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceMulticastAddrMessage struct { Header IfmaMsghdr Data []byte diff --git a/src/syscall/route_freebsd.go b/src/syscall/route_freebsd.go index fbfafbc1025521..2c2de7474a4415 100644 --- a/src/syscall/route_freebsd.go +++ b/src/syscall/route_freebsd.go @@ -53,6 +53,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { // InterfaceAnnounceMessage represents a routing message containing // network interface arrival and departure information. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } @@ -61,6 +63,8 @@ func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, // InterfaceMulticastAddrMessage represents a routing message // containing network interface address entries. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceMulticastAddrMessage struct { Header IfmaMsghdr Data []byte diff --git a/src/syscall/route_ifma_test.go b/src/syscall/route_ifma_test.go deleted file mode 100644 index af2b67dc24492e..00000000000000 --- a/src/syscall/route_ifma_test.go +++ /dev/null @@ -1,74 +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. - -// +build darwin dragonfly freebsd - -package syscall_test - -import ( - "fmt" - "syscall" -) - -func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) { - switch m := m.(type) { - case *syscall.RouteMessage: - errno := syscall.Errno(uintptr(m.Header.Errno)) - if errno != 0 { - return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header) - } - return addrFlags(m.Header.Addrs), nil - case *syscall.InterfaceMessage: - return addrFlags(m.Header.Addrs), nil - case *syscall.InterfaceAddrMessage: - return addrFlags(m.Header.Addrs), nil - case *syscall.InterfaceMulticastAddrMessage: - return addrFlags(m.Header.Addrs), nil - default: - panic(fmt.Sprintf("unknown routing message type: %T", m)) - } -} - -func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) { - switch m := m.(type) { - case *syscall.RouteMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - case *syscall.InterfaceMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - case *syscall.InterfaceAddrMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - case *syscall.InterfaceMulticastAddrMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - default: - panic(fmt.Sprintf("unknown routing message type: %T", m)) - } -} diff --git a/src/syscall/route_netbsd.go b/src/syscall/route_netbsd.go index d21e3fa32c49c9..a10c8b65d9dbc2 100644 --- a/src/syscall/route_netbsd.go +++ b/src/syscall/route_netbsd.go @@ -28,6 +28,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { // InterfaceAnnounceMessage represents a routing message containing // network interface arrival and departure information. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } diff --git a/src/syscall/route_noifma_test.go b/src/syscall/route_noifma_test.go deleted file mode 100644 index 19d5d8ebbf277e..00000000000000 --- a/src/syscall/route_noifma_test.go +++ /dev/null @@ -1,63 +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. - -// +build netbsd openbsd - -package syscall_test - -import ( - "fmt" - "syscall" -) - -func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) { - switch m := m.(type) { - case *syscall.RouteMessage: - errno := syscall.Errno(uintptr(m.Header.Errno)) - if errno != 0 { - return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header) - } - return addrFlags(m.Header.Addrs), nil - case *syscall.InterfaceMessage: - return addrFlags(m.Header.Addrs), nil - case *syscall.InterfaceAddrMessage: - return addrFlags(m.Header.Addrs), nil - default: - panic(fmt.Sprintf("unknown routing message type: %T", m)) - } -} - -func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) { - switch m := m.(type) { - case *syscall.RouteMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - case *syscall.InterfaceMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - case *syscall.InterfaceAddrMessage: - sas, err := syscall.ParseRoutingSockaddr(m) - if err != nil { - return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data) - } - if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil { - return nil, err - } - return sas, nil - default: - panic(fmt.Sprintf("unknown routing message type: %T", m)) - } -} diff --git a/src/syscall/route_openbsd.go b/src/syscall/route_openbsd.go index 719396db53beb0..fe173adda8879e 100644 --- a/src/syscall/route_openbsd.go +++ b/src/syscall/route_openbsd.go @@ -28,6 +28,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { // InterfaceAnnounceMessage represents a routing message containing // network interface arrival and departure information. +// +// Deprecated: Use golang.org/x/net/route instead. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } From 5fae488633ff247b9b7964dc45b8fe4b491f5a16 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sun, 15 May 2016 17:16:04 +0900 Subject: [PATCH 107/267] syscall: deprecate BPF/LSF Updates #14982. Change-Id: Id12b1e61456832d2b2ffbdbe8cf0a1db4444b1e4 Reviewed-on: https://go-review.googlesource.com/23122 Reviewed-by: Brad Fitzpatrick --- src/syscall/bpf_bsd.go | 18 ++++++++++++++++++ src/syscall/lsf_linux.go | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/src/syscall/bpf_bsd.go b/src/syscall/bpf_bsd.go index 2523e9b001a560..8b587559edbcba 100644 --- a/src/syscall/bpf_bsd.go +++ b/src/syscall/bpf_bsd.go @@ -12,14 +12,17 @@ import ( "unsafe" ) +// Deprecated: Use golang.org/x/net/bpf instead. func BpfStmt(code, k int) *BpfInsn { return &BpfInsn{Code: uint16(code), K: uint32(k)} } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfJump(code, k, jt, jf int) *BpfInsn { return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)} } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfBuflen(fd int) (int, error) { var l int _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l))) @@ -29,6 +32,7 @@ func BpfBuflen(fd int) (int, error) { return l, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfBuflen(fd, l int) (int, error) { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l))) if err != 0 { @@ -37,6 +41,7 @@ func SetBpfBuflen(fd, l int) (int, error) { return l, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfDatalink(fd int) (int, error) { var t int _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t))) @@ -46,6 +51,7 @@ func BpfDatalink(fd int) (int, error) { return t, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfDatalink(fd, t int) (int, error) { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t))) if err != 0 { @@ -54,6 +60,7 @@ func SetBpfDatalink(fd, t int) (int, error) { return t, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfPromisc(fd, m int) error { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m))) if err != 0 { @@ -62,6 +69,7 @@ func SetBpfPromisc(fd, m int) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func FlushBpf(fd int) error { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0) if err != 0 { @@ -75,6 +83,7 @@ type ivalue struct { value int16 } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfInterface(fd int, name string) (string, error) { var iv ivalue _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv))) @@ -84,6 +93,7 @@ func BpfInterface(fd int, name string) (string, error) { return name, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfInterface(fd int, name string) error { var iv ivalue copy(iv.name[:], []byte(name)) @@ -94,6 +104,7 @@ func SetBpfInterface(fd int, name string) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfTimeout(fd int) (*Timeval, error) { var tv Timeval _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv))) @@ -103,6 +114,7 @@ func BpfTimeout(fd int) (*Timeval, error) { return &tv, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfTimeout(fd int, tv *Timeval) error { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv))) if err != 0 { @@ -111,6 +123,7 @@ func SetBpfTimeout(fd int, tv *Timeval) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfStats(fd int) (*BpfStat, error) { var s BpfStat _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s))) @@ -120,6 +133,7 @@ func BpfStats(fd int) (*BpfStat, error) { return &s, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfImmediate(fd, m int) error { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m))) if err != 0 { @@ -128,6 +142,7 @@ func SetBpfImmediate(fd, m int) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpf(fd int, i []BpfInsn) error { var p BpfProgram p.Len = uint32(len(i)) @@ -139,6 +154,7 @@ func SetBpf(fd int, i []BpfInsn) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func CheckBpfVersion(fd int) error { var v BpfVersion _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v))) @@ -151,6 +167,7 @@ func CheckBpfVersion(fd int) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func BpfHeadercmpl(fd int) (int, error) { var f int _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f))) @@ -160,6 +177,7 @@ func BpfHeadercmpl(fd int) (int, error) { return f, nil } +// Deprecated: Use golang.org/x/net/bpf instead. func SetBpfHeadercmpl(fd, f int) error { _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f))) if err != 0 { diff --git a/src/syscall/lsf_linux.go b/src/syscall/lsf_linux.go index 4a6aa2d6eb5329..b89239eba8a457 100644 --- a/src/syscall/lsf_linux.go +++ b/src/syscall/lsf_linux.go @@ -10,14 +10,17 @@ import ( "unsafe" ) +// Deprecated: Use golang.org/x/net/bpf instead. func LsfStmt(code, k int) *SockFilter { return &SockFilter{Code: uint16(code), K: uint32(k)} } +// Deprecated: Use golang.org/x/net/bpf instead. func LsfJump(code, k, jt, jf int) *SockFilter { return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)} } +// Deprecated: Use golang.org/x/net/bpf instead. func LsfSocket(ifindex, proto int) (int, error) { var lsall SockaddrLinklayer s, e := Socket(AF_PACKET, SOCK_RAW, proto) @@ -41,6 +44,7 @@ type iflags struct { flags uint16 } +// Deprecated: Use golang.org/x/net/bpf instead. func SetLsfPromisc(name string, m bool) error { s, e := Socket(AF_INET, SOCK_DGRAM, 0) if e != nil { @@ -65,6 +69,7 @@ func SetLsfPromisc(name string, m bool) error { return nil } +// Deprecated: Use golang.org/x/net/bpf instead. func AttachLsf(fd int, i []SockFilter) error { var p SockFprog p.Len = uint16(len(i)) @@ -72,6 +77,7 @@ func AttachLsf(fd int, i []SockFilter) error { return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p)) } +// Deprecated: Use golang.org/x/net/bpf instead. func DetachLsf(fd int) error { var dummy int return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy)) From a101b85e00f302706d8b1de1d2173a154d5f54cc Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sun, 15 May 2016 17:24:51 +0900 Subject: [PATCH 108/267] syscall: fix missing use of use function in sysctl Updates #13372. Change-Id: Id2402a781474e9d0bb0901c5844adbd899f76cbd Reviewed-on: https://go-review.googlesource.com/23123 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/syscall/zsyscall_darwin_386.go | 1 + src/syscall/zsyscall_darwin_amd64.go | 1 + src/syscall/zsyscall_darwin_arm.go | 1 + src/syscall/zsyscall_dragonfly_amd64.go | 1 + src/syscall/zsyscall_freebsd_386.go | 1 + src/syscall/zsyscall_freebsd_amd64.go | 1 + src/syscall/zsyscall_freebsd_arm.go | 1 + src/syscall/zsyscall_netbsd_386.go | 1 + src/syscall/zsyscall_netbsd_amd64.go | 1 + src/syscall/zsyscall_netbsd_arm.go | 1 + src/syscall/zsyscall_openbsd_386.go | 1 + src/syscall/zsyscall_openbsd_amd64.go | 1 + 12 files changed, 12 insertions(+) diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go index 23e7b5e420bac3..9c3ba5a81a0515 100644 --- a/src/syscall/zsyscall_darwin_386.go +++ b/src/syscall/zsyscall_darwin_386.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 6e63d9a0743fa9..12f4782296c5e5 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go index f996a508f020a1..ab5b4a97bab7ad 100644 --- a/src/syscall/zsyscall_darwin_arm.go +++ b/src/syscall/zsyscall_darwin_arm.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 88e09d3a14d211..85d27777ba7483 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go index 30f29e52a9f6fe..b9ed271486b8ca 100644 --- a/src/syscall/zsyscall_freebsd_386.go +++ b/src/syscall/zsyscall_freebsd_386.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go index 93059d1b5bbb10..12d1db0c86186e 100644 --- a/src/syscall/zsyscall_freebsd_amd64.go +++ b/src/syscall/zsyscall_freebsd_amd64.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go index 84096b07a59bff..78b7c07a0fa591 100644 --- a/src/syscall/zsyscall_freebsd_arm.go +++ b/src/syscall/zsyscall_freebsd_arm.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go index e24c3b71cdad79..61b52cd165fea9 100644 --- a/src/syscall/zsyscall_netbsd_386.go +++ b/src/syscall/zsyscall_netbsd_386.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go index 7aa75ab12df43d..52987ba9023702 100644 --- a/src/syscall/zsyscall_netbsd_amd64.go +++ b/src/syscall/zsyscall_netbsd_amd64.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go index 21f482b40fdf0e..5c59a0ded161ac 100644 --- a/src/syscall/zsyscall_netbsd_arm.go +++ b/src/syscall/zsyscall_netbsd_arm.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index df7df1e7e457ee..37bbd85de5c560 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 1d640700f7d6a8..0d831df1f67eb1 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _p0 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + use(_p0) if e1 != 0 { err = errnoErr(e1) } From 6a6c1d9841a1957a2fd292df776ea920ae38ea00 Mon Sep 17 00:00:00 2001 From: Artyom Pervukhin Date: Mon, 16 May 2016 15:30:28 +0300 Subject: [PATCH 109/267] net/http/httputil: don't add User-Agent header by proxy made with NewSingleHostReverseProxy If client does not provided User-Agent header, do not set default one used by net/http package when doing request to backend. Fixes #15524 Change-Id: I9a46bb3b7ec106bc7c3071e235b872d279994d67 Reviewed-on: https://go-review.googlesource.com/23089 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/http/httputil/reverseproxy.go | 4 ++ src/net/http/httputil/reverseproxy_test.go | 43 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 44d15ff6be7f08..49c120afde12fc 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -90,6 +90,10 @@ func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy { } else { req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery } + if _, ok := req.Header["User-Agent"]; !ok { + // explicitly disable User-Agent so it's not set to default value + req.Header.Set("User-Agent", "") + } } return &ReverseProxy{Director: director} } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index e9c0658271f06c..fe7cdb888f5ced 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -348,6 +348,49 @@ func TestNilBody(t *testing.T) { } } +// Issue 15524 +func TestUserAgentHeader(t *testing.T) { + const explicitUA = "explicit UA" + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/noua" { + if c := r.Header.Get("User-Agent"); c != "" { + t.Errorf("handler got non-empty User-Agent header %q", c) + } + return + } + if c := r.Header.Get("User-Agent"); c != explicitUA { + t.Errorf("handler got unexpected User-Agent header %q", c) + } + })) + defer backend.Close() + backendURL, err := url.Parse(backend.URL) + if err != nil { + t.Fatal(err) + } + proxyHandler := NewSingleHostReverseProxy(backendURL) + proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + frontend := httptest.NewServer(proxyHandler) + defer frontend.Close() + + getReq, _ := http.NewRequest("GET", frontend.URL, nil) + getReq.Header.Set("User-Agent", explicitUA) + getReq.Close = true + res, err := http.DefaultClient.Do(getReq) + if err != nil { + t.Fatalf("Get: %v", err) + } + res.Body.Close() + + getReq, _ = http.NewRequest("GET", frontend.URL+"/noua", nil) + getReq.Header.Set("User-Agent", "") + getReq.Close = true + res, err = http.DefaultClient.Do(getReq) + if err != nil { + t.Fatalf("Get: %v", err) + } + res.Body.Close() +} + type bufferPool struct { get func() []byte put func([]byte) From b66b97e0a120880e37b03eba00c0c7679f0a70c1 Mon Sep 17 00:00:00 2001 From: Dan Peterson Date: Mon, 16 May 2016 10:11:59 -0300 Subject: [PATCH 110/267] net/http: mention ALPN in http.Server.TLSNextProto documentation Make clear negotiation can happen via NPN or ALPN, similar to http.Transport.TLSNextProto and x/net/http2.NextProtoTLS. Change-Id: Ied00b842bc04e11159d6d2107beda921cefbc6ca Reviewed-on: https://go-review.googlesource.com/23108 Reviewed-by: Brad Fitzpatrick --- src/net/http/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index d0be7d01dbd0aa..d4e38b6ad09420 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2082,7 +2082,7 @@ type Server struct { MaxHeaderBytes int // TLSNextProto optionally specifies a function to take over - // ownership of the provided TLS connection when an NPN + // ownership of the provided TLS connection when an NPN/ALPN // protocol upgrade has occurred. The map key is the protocol // name negotiated. The Handler argument should be used to // handle HTTP requests and will initialize the Request's TLS From 30ded16596246c719ede90acf45ecb31d8f428f6 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 11 May 2016 16:29:07 -0400 Subject: [PATCH 111/267] runtime: remove obsolete comment from scanobject Change-Id: I5ebf93b60213c0138754fc20888ae5ce60237b8c Reviewed-on: https://go-review.googlesource.com/23131 Reviewed-by: Rick Hudson --- src/runtime/mgcmark.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index af3205ab2332bf..5d947fb59e6d50 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -1096,7 +1096,7 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) { // scanobject scans the object starting at b, adding pointers to gcw. // b must point to the beginning of a heap object; scanobject consults // the GC bitmap for the pointer mask and the spans for the size of the -// object (it ignores n). +// object. //go:nowritebarrier func scanobject(b uintptr, gcw *gcWork) { // Note that arena_used may change concurrently during From 64770f642fe4b2f3af6f30d1e058e934e73d0b9b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 9 May 2016 11:29:34 -0400 Subject: [PATCH 112/267] runtime: use conventional shift style for gcBitsChunkBytes The convention for writing something like "64 kB" is 64<<10, since this is easier to read than 1<<16. Update gcBitsChunkBytes to follow this convention. Change-Id: I5b5a3f726dcf482051ba5b1814db247ff3b8bb2f Reviewed-on: https://go-review.googlesource.com/23132 Reviewed-by: Rick Hudson --- src/runtime/mheap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 46b7048c4092da..4093288a7cb382 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -1243,7 +1243,7 @@ func freespecial(s *special, p unsafe.Pointer, size uintptr) { } } -const gcBitsChunkBytes = uintptr(1 << 16) +const gcBitsChunkBytes = uintptr(64 << 10) const gcBitsHeaderBytes = unsafe.Sizeof(gcBitsHeader{}) type gcBitsHeader struct { From 181000896e381f07e8f105eef2667d566729f6eb Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 16 May 2016 12:36:02 -0700 Subject: [PATCH 113/267] encoding/json: document that object keys are sorted Fixes #15424 Change-Id: Ib9e97509f5ac239ee54fe6fe37152a7f5fc75087 Reviewed-on: https://go-review.googlesource.com/23109 Reviewed-by: Brad Fitzpatrick --- src/encoding/json/encode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 8b967471ce70fc..f91a78724cf44d 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -119,8 +119,8 @@ import ( // // Map values encode as JSON objects. The map's key type must either be a // string, an integer type, or implement encoding.TextMarshaler. The map keys -// are used as JSON object keys by applying the following rules, subject to the -// UTF-8 coercion described for string values above: +// are sorted and used as JSON object keys by applying the following rules, +// subject to the UTF-8 coercion described for string values above: // - string keys are used directly // - encoding.TextMarshalers are marshaled // - integer keys are converted to strings From 466cae6ca9f28c971a2d716a5a49dc76bbd1d5bb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 16 May 2016 15:27:48 -0400 Subject: [PATCH 114/267] runtime: use GOTRACEBACK=system for TestStackBarrierProfiling This should help with debugging failures. For #15138 and #15477. Change-Id: I77db2b6375d8b4403d3edf5527899d076291e02c Reviewed-on: https://go-review.googlesource.com/23134 Run-TryBot: Austin Clements Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/pprof/pprof_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 8b2f3d5291ee12..3852d93e7264c6 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -388,7 +388,7 @@ func TestStackBarrierProfiling(t *testing.T) { args = append(args, "-test.short") } cmd := exec.Command(os.Args[0], args...) - cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1"}, os.Environ()...) + cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1", "GOTRACEBACK=system"}, os.Environ()...) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("subprocess failed with %v:\n%s", err, out) } From 6b99fb5bea56b9674161b6c5415c1d05f19dfdc6 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 21 Apr 2016 13:24:58 -0400 Subject: [PATCH 115/267] cmd/compile: use sparse algorithm for phis in large program This adds a sparse method for locating nearest ancestors in a dominator tree, and checks blocks with more than one predecessor for differences and inserts phi functions where there are. Uses reversed post order to cut number of passes, running it from first def to last use ("last use" for paramout and mem is end-of-program; last use for a phi input from a backedge is the source of the back edge) Includes a cutover from old algorithm to new to avoid paying large constant factor for small programs. This keeps normal builds running at about the same time, while not running over-long on large machine-generated inputs. Add "phase" flags for ssa/build -- ssa/build/stats prints number of blocks, values (before and after linking references and inserting phis, so expansion can be measured), and their product; the product governs the cutover, where a good value seems to be somewhere between 1 and 5 million. Among the files compiled by make.bash, this is the shape of the tail of the distribution for #blocks, #vars, and their product: #blocks #vars product max 6171 28180 173,898,780 99.9% 1641 6548 10,401,878 99% 463 1909 873,721 95% 152 639 95,235 90% 84 359 30,021 The old algorithm is indeed usually fastest, for 99%ile values of usually. The fix to LookupVarOutgoing ( https://go-review.googlesource.com/#/c/22790/ ) deals with some of the same problems addressed by this CL, but on at least one bug ( #15537 ) this change is still a significant help. With this CL: /tmp/gopath$ rm -rf pkg bin /tmp/gopath$ time go get -v -gcflags -memprofile=y.mprof \ github.com/gogo/protobuf/test/theproto3/combos/... ... real 4m35.200s user 13m16.644s sys 0m36.712s and pprof reports 3.4GB allocated in one of the larger profiles With tip: /tmp/gopath$ rm -rf pkg bin /tmp/gopath$ time go get -v -gcflags -memprofile=y.mprof \ github.com/gogo/protobuf/test/theproto3/combos/... ... real 10m36.569s user 25m52.286s sys 4m3.696s and pprof reports 8.3GB allocated in the same larger profile With this CL, most of the compilation time on the benchmarked input is spent in register/stack allocation (cumulative 53%) and in the sparse lookup algorithm itself (cumulative 20%). Fixes #15537. Change-Id: Ia0299dda6a291534d8b08e5f9883216ded677a00 Reviewed-on: https://go-review.googlesource.com/22342 Reviewed-by: Keith Randall Run-TryBot: David Chase TryBot-Result: Gobot Gobot --- .../internal/gc/sparselocatephifunctions.go | 199 ++++++++ src/cmd/compile/internal/gc/ssa.go | 18 +- src/cmd/compile/internal/ssa/check.go | 2 +- src/cmd/compile/internal/ssa/compile.go | 21 +- src/cmd/compile/internal/ssa/config.go | 49 +- src/cmd/compile/internal/ssa/cse.go | 4 +- src/cmd/compile/internal/ssa/dom.go | 6 +- src/cmd/compile/internal/ssa/func.go | 10 +- src/cmd/compile/internal/ssa/likelyadjust.go | 8 +- src/cmd/compile/internal/ssa/prove.go | 2 +- src/cmd/compile/internal/ssa/redblack32.go | 429 ++++++++++++++++++ .../compile/internal/ssa/redblack32_test.go | 276 +++++++++++ src/cmd/compile/internal/ssa/regalloc.go | 2 +- src/cmd/compile/internal/ssa/sparsetree.go | 49 +- src/cmd/compile/internal/ssa/sparsetreemap.go | 169 +++++++ src/cmd/compile/internal/ssa/stackalloc.go | 2 +- 16 files changed, 1194 insertions(+), 52 deletions(-) create mode 100644 src/cmd/compile/internal/gc/sparselocatephifunctions.go create mode 100644 src/cmd/compile/internal/ssa/redblack32.go create mode 100644 src/cmd/compile/internal/ssa/redblack32_test.go create mode 100644 src/cmd/compile/internal/ssa/sparsetreemap.go diff --git a/src/cmd/compile/internal/gc/sparselocatephifunctions.go b/src/cmd/compile/internal/gc/sparselocatephifunctions.go new file mode 100644 index 00000000000000..e15f22123f7262 --- /dev/null +++ b/src/cmd/compile/internal/gc/sparselocatephifunctions.go @@ -0,0 +1,199 @@ +// 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 ( + "cmd/compile/internal/ssa" + "fmt" + "math" +) + +// sparseDefState contains a Go map from ONAMEs (*Node) to sparse definition trees, and +// a search helper for the CFG's dominator tree in which those definitions are embedded. +// Once initialized, given a use of an ONAME within a block, the ssa definition for +// that ONAME can be discovered in time roughly proportional to the log of the number +// of SSA definitions of that ONAME (thus avoiding pathological quadratic behavior for +// very large programs). The helper contains state (a dominator tree numbering) common +// to all the sparse definition trees, as well as some necessary data obtained from +// the ssa package. +// +// This algorithm has improved asymptotic complexity, but the constant factor is +// rather large and thus it is only preferred for very large inputs containing +// 1000s of blocks and variables. +type sparseDefState struct { + helper *ssa.SparseTreeHelper // contains one copy of information needed to do sparse mapping + defmapForOname map[*Node]*onameDefs // for each ONAME, its definition set (normal and phi) +} + +// onameDefs contains a record of definitions (ordinary and implied phi function) for a single OName. +// stm is the set of definitions for the OName. +// firstdef and lastuse are postorder block numberings that +// conservatively bracket the entire lifetime of the OName. +type onameDefs struct { + stm *ssa.SparseTreeMap + // firstdef and lastuse define an interval in the postorder numbering + // that is guaranteed to include the entire lifetime of an ONAME. + // In the postorder numbering, math.MaxInt32 is before anything, + // and 0 is after-or-equal all exit nodes and infinite loops. + firstdef int32 // the first definition of this ONAME *in the postorder numbering* + lastuse int32 // the last use of this ONAME *in the postorder numbering* +} + +// defsFor finds or creates-and-inserts-in-map the definition information +// (sparse tree and live range) for a given OName. +func (m *sparseDefState) defsFor(n *Node) *onameDefs { + d := m.defmapForOname[n] + if d != nil { + return d + } + // Reminder: firstdef/lastuse are postorder indices, not block indices, + // so these default values define an empty interval, not the entire one. + d = &onameDefs{stm: m.helper.NewTree(), firstdef: 0, lastuse: math.MaxInt32} + m.defmapForOname[n] = d + return d +} + +// Insert adds a definition at b (with specified before/within/after adjustment) +// to sparse tree onameDefs. The lifetime is extended as necessary. +func (m *sparseDefState) Insert(tree *onameDefs, b *ssa.Block, adjust int32) { + bponum := m.helper.Ponums[b.ID] + if bponum > tree.firstdef { + tree.firstdef = bponum + } + tree.stm.Insert(b, adjust, b, m.helper) +} + +// Use updates tree to record a use within b, extending the lifetime as necessary. +func (m *sparseDefState) Use(tree *onameDefs, b *ssa.Block) { + bponum := m.helper.Ponums[b.ID] + if bponum < tree.lastuse { + tree.lastuse = bponum + } +} + +// locatePotentialPhiFunctions finds all the places where phi functions +// will be inserted into a program and records those and ordinary definitions +// in a "map" (not a Go map) that given an OName and use site, returns the +// SSA definition for that OName that will reach the use site (that is, +// the use site's nearest def/phi site in the dominator tree.) +func (s *state) locatePotentialPhiFunctions(fn *Node) *sparseDefState { + // s.config.SparsePhiCutoff() is compared with product of numblocks and numvalues, + // if product is smaller than cutoff, use old non-sparse method. + // cutoff == 0 implies all sparse + // cutoff == uint(-1) implies all non-sparse + if uint64(s.f.NumValues())*uint64(s.f.NumBlocks()) < s.config.SparsePhiCutoff() { + return nil + } + + helper := ssa.NewSparseTreeHelper(s.f) + po := helper.Po // index by block.ID to obtain postorder # of block. + trees := make(map[*Node]*onameDefs) + dm := &sparseDefState{defmapForOname: trees, helper: helper} + + // Process params, taking note of their special lifetimes + b := s.f.Entry + for _, n := range fn.Func.Dcl { + switch n.Class { + case PPARAM, PPARAMOUT: + t := dm.defsFor(n) + dm.Insert(t, b, ssa.AdjustBefore) // define param at entry block + if n.Class == PPARAMOUT { + dm.Use(t, po[0]) // Explicitly use PPARAMOUT at very last block + } + default: + } + } + + // Process memory variable. + t := dm.defsFor(&memVar) + dm.Insert(t, b, ssa.AdjustBefore) // define memory at entry block + dm.Use(t, po[0]) // Explicitly use memory at last block + + // Next load the map w/ basic definitions for ONames recorded per-block + // Iterate over po to avoid unreachable blocks. + for i := len(po) - 1; i >= 0; i-- { + b := po[i] + m := s.defvars[b.ID] + for n := range m { // no specified order, but per-node trees are independent. + t := dm.defsFor(n) + dm.Insert(t, b, ssa.AdjustWithin) + } + } + + // Find last use of each variable + for _, v := range s.fwdRefs { + b := v.Block + name := v.Aux.(*Node) + t := dm.defsFor(name) + dm.Use(t, b) + } + + for _, t := range trees { + // iterating over names in the outer loop + for change := true; change; { + change = false + for i := t.firstdef; i >= t.lastuse; i-- { + // Iterating in reverse of post-order reduces number of 'change' iterations; + // all possible forward flow goes through each time. + b := po[i] + // Within tree t, would a use at b require a phi function to ensure a single definition? + // TODO: perhaps more efficient to record specific use sites instead of range? + if len(b.Preds) < 2 { + continue // no phi possible + } + phi := t.stm.Find(b, ssa.AdjustWithin, helper) // Look for defs in earlier block or AdjustBefore in this one. + if phi != nil && phi.(*ssa.Block) == b { + continue // has a phi already in this block. + } + var defseen interface{} + // Do preds see different definitions? if so, need a phi function. + for _, e := range b.Preds { + p := e.Block() + dm.Use(t, p) // always count phi pred as "use"; no-op except for loop edges, which matter. + x := t.stm.Find(p, ssa.AdjustAfter, helper) // Look for defs reaching or within predecessors. + if defseen == nil { + defseen = x + } + if defseen != x || x == nil { // TODO: too conservative at loops, does better if x == nil -> continue + // Need to insert a phi function here because predecessors's definitions differ. + change = true + // Phi insertion is at AdjustBefore, visible with find in same block at AdjustWithin or AdjustAfter. + dm.Insert(t, b, ssa.AdjustBefore) + break + } + } + } + } + } + return dm +} + +// FindBetterDefiningBlock tries to find a better block for a definition of OName name +// reaching (or within) p than p itself. If it cannot, it returns p instead. +// This aids in more efficient location of phi functions, since it can skip over +// branch code that might contain a definition of name if it actually does not. +func (m *sparseDefState) FindBetterDefiningBlock(name *Node, p *ssa.Block) *ssa.Block { + if m == nil { + return p + } + t := m.defmapForOname[name] + // For now this is fail-soft, since the old algorithm still works using the unimproved block. + if t == nil { + return p + } + x := t.stm.Find(p, ssa.AdjustAfter, m.helper) + if x == nil { + return p + } + b := x.(*ssa.Block) + if b == nil { + return p + } + return b +} + +func (d *onameDefs) String() string { + return fmt.Sprintf("onameDefs:first=%d,last=%d,tree=%s", d.firstdef, d.lastuse, d.stm.String()) +} diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 19af92100a8ca6..fdf040d5af93bd 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -218,8 +218,16 @@ func buildssa(fn *Node) *ssa.Func { return nil } + prelinkNumvars := s.f.NumValues() + sparseDefState := s.locatePotentialPhiFunctions(fn) + // Link up variable uses to variable definitions - s.linkForwardReferences() + s.linkForwardReferences(sparseDefState) + + if ssa.BuildStats > 0 { + s.f.LogStat("build", s.f.NumBlocks(), "blocks", prelinkNumvars, "vars_before", + s.f.NumValues(), "vars_after", prelinkNumvars*s.f.NumBlocks(), "ssa_phi_loc_cutoff_score") + } // Don't carry reference this around longer than necessary s.exitCode = Nodes{} @@ -3741,7 +3749,8 @@ func (s *state) mem() *ssa.Value { return s.variable(&memVar, ssa.TypeMem) } -func (s *state) linkForwardReferences() { +func (s *state) linkForwardReferences(dm *sparseDefState) { + // Build SSA graph. Each variable on its first use in a basic block // leaves a FwdRef in that block representing the incoming value // of that variable. This function links that ref up with possible definitions, @@ -3756,13 +3765,13 @@ func (s *state) linkForwardReferences() { for len(s.fwdRefs) > 0 { v := s.fwdRefs[len(s.fwdRefs)-1] s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1] - s.resolveFwdRef(v) + s.resolveFwdRef(v, dm) } } // resolveFwdRef modifies v to be the variable's value at the start of its block. // v must be a FwdRef op. -func (s *state) resolveFwdRef(v *ssa.Value) { +func (s *state) resolveFwdRef(v *ssa.Value, dm *sparseDefState) { b := v.Block name := v.Aux.(*Node) v.Aux = nil @@ -3801,6 +3810,7 @@ func (s *state) resolveFwdRef(v *ssa.Value) { args := argstore[:0] for _, e := range b.Preds { p := e.Block() + p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line)) } diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 60be3de5218ad9..bfedd477946b53 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -316,7 +316,7 @@ func checkFunc(f *Func) { } // domCheck reports whether x dominates y (including x==y). -func domCheck(f *Func, sdom sparseTree, x, y *Block) bool { +func domCheck(f *Func, sdom SparseTree, x, y *Block) bool { if !sdom.isAncestorEq(f.Entry, y) { // unreachable - ignore return true diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index bc9c830ee958aa..b3c7544ad129ab 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -86,14 +86,14 @@ func Compile(f *Func) { // Surround timing information w/ enough context to allow comparisons. time := tEnd.Sub(tStart).Nanoseconds() if p.time { - f.logStat("TIME(ns)", time) + f.LogStat("TIME(ns)", time) } if p.mem { var mEnd runtime.MemStats runtime.ReadMemStats(&mEnd) nBytes := mEnd.TotalAlloc - mStart.TotalAlloc nAllocs := mEnd.Mallocs - mStart.Mallocs - f.logStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs) + f.LogStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs) } } if checkEnabled { @@ -124,6 +124,10 @@ var checkEnabled = false var IntrinsicsDebug int var IntrinsicsDisable bool +var BuildDebug int +var BuildTest int +var BuildStats int + // PhaseOption sets the specified flag in the specified ssa phase, // returning empty string if this was successful or a string explaining // the error if it was not. @@ -174,6 +178,19 @@ func PhaseOption(phase, flag string, val int) string { } return "" } + if phase == "build" { + switch flag { + case "debug": + BuildDebug = val + case "test": + BuildTest = val + case "stats": + BuildStats = val + default: + return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase) + } + return "" + } underphase := strings.Replace(phase, "_", " ", -1) var re *regexp.Regexp diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 2a676e39b3a1f7..e8ab17806c0e15 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -9,22 +9,24 @@ import ( "crypto/sha1" "fmt" "os" + "strconv" "strings" ) type Config struct { - arch string // "amd64", etc. - IntSize int64 // 4 or 8 - PtrSize int64 // 4 or 8 - lowerBlock func(*Block) bool // lowering function - lowerValue func(*Value, *Config) bool // lowering function - registers []Register // machine registers - fe Frontend // callbacks into compiler frontend - HTML *HTMLWriter // html writer, for debugging - ctxt *obj.Link // Generic arch information - optimize bool // Do optimization - noDuffDevice bool // Don't use Duff's device - curFunc *Func + arch string // "amd64", etc. + IntSize int64 // 4 or 8 + PtrSize int64 // 4 or 8 + lowerBlock func(*Block) bool // lowering function + lowerValue func(*Value, *Config) bool // lowering function + registers []Register // machine registers + fe Frontend // callbacks into compiler frontend + HTML *HTMLWriter // html writer, for debugging + ctxt *obj.Link // Generic arch information + optimize bool // Do optimization + noDuffDevice bool // Don't use Duff's device + sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score + curFunc *Func // TODO: more stuff. Compiler flags of interest, ... @@ -159,10 +161,27 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config c.logfiles = make(map[string]*os.File) + // cutoff is compared with product of numblocks and numvalues, + // if product is smaller than cutoff, use old non-sparse method. + // cutoff == 0 implies all sparse. + // cutoff == -1 implies none sparse. + // Good cutoff values seem to be O(million) depending on constant factor cost of sparse. + // TODO: get this from a flag, not an environment variable + c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash + ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF") + if ev != "" { + v, err := strconv.ParseInt(ev, 10, 64) + if err != nil { + fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev) + } + c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse + } + return c } -func (c *Config) Frontend() Frontend { return c.fe } +func (c *Config) Frontend() Frontend { return c.fe } +func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff } // NewFunc returns a new, empty function object. // Caller must call f.Free() before calling NewFunc again. @@ -259,3 +278,7 @@ func (c *Config) DebugHashMatch(evname, name string) bool { } return false } + +func (c *Config) DebugNameMatch(evname, name string) bool { + return os.Getenv(evname) == name +} diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index 8cc0db1d17266e..20ea45ab3e139a 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -190,7 +190,7 @@ func cse(f *Func) { } } if f.pass.stats > 0 { - f.logStat("CSE REWRITES", rewrites) + f.LogStat("CSE REWRITES", rewrites) } } @@ -313,7 +313,7 @@ func (sv sortvalues) Less(i, j int) bool { type sortbyentry struct { a []*Value // array of values - sdom sparseTree + sdom SparseTree } func (sv sortbyentry) Len() int { return len(sv.a) } diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index 78ba2e9e1b6aae..0c532c87ff7211 100644 --- a/src/cmd/compile/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go @@ -20,9 +20,9 @@ const ( // postorder computes a postorder traversal ordering for the // basic blocks in f. Unreachable blocks will not appear. func postorder(f *Func) []*Block { - return postorderWithNumbering(f, []int{}) + return postorderWithNumbering(f, []int32{}) } -func postorderWithNumbering(f *Func, ponums []int) []*Block { +func postorderWithNumbering(f *Func, ponums []int32) []*Block { mark := make([]markKind, f.NumBlocks()) // result ordering @@ -40,7 +40,7 @@ func postorderWithNumbering(f *Func, ponums []int) []*Block { s = s[:len(s)-1] mark[b.ID] = done if len(ponums) > 0 { - ponums[b.ID] = len(order) + ponums[b.ID] = int32(len(order)) } order = append(order, b) case notExplored: diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 2c7a8a1f11e1fc..1d60bb606ad226 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -37,7 +37,7 @@ type Func struct { freeBlocks *Block // free Blocks linked by succstorage[0].b. All other fields except ID are 0/nil. idom []*Block // precomputed immediate dominators - sdom sparseTree // precomputed dominator tree + sdom SparseTree // precomputed dominator tree constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type } @@ -104,12 +104,16 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value { // context to allow item-by-item comparisons across runs. // For example: // awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log -func (f *Func) logStat(key string, args ...interface{}) { +func (f *Func) LogStat(key string, args ...interface{}) { value := "" for _, a := range args { value += fmt.Sprintf("\t%v", a) } - f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", f.pass.name, key, value, f.Name) + n := "missing_pass" + if f.pass != nil { + n = f.pass.name + } + f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name) } // freeValue frees a value. It must no longer be referenced. diff --git a/src/cmd/compile/internal/ssa/likelyadjust.go b/src/cmd/compile/internal/ssa/likelyadjust.go index 3f03943a7418d9..cb2d82f3527640 100644 --- a/src/cmd/compile/internal/ssa/likelyadjust.go +++ b/src/cmd/compile/internal/ssa/likelyadjust.go @@ -32,7 +32,7 @@ type loop struct { } // outerinner records that outer contains inner -func (sdom sparseTree) outerinner(outer, inner *loop) { +func (sdom SparseTree) outerinner(outer, inner *loop) { oldouter := inner.outer if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) { inner.outer = outer @@ -59,7 +59,7 @@ type loopnest struct { f *Func b2l []*loop po []*Block - sdom sparseTree + sdom SparseTree loops []*loop // Record which of the lazily initialized fields have actually been initialized. @@ -238,7 +238,7 @@ func (l *loop) LongString() string { // containing block b; the header must dominate b. loop itself // is assumed to not be that loop. For acceptable performance, // we're relying on loop nests to not be terribly deep. -func (l *loop) nearestOuterLoop(sdom sparseTree, b *Block) *loop { +func (l *loop) nearestOuterLoop(sdom SparseTree, b *Block) *loop { var o *loop for o = l.outer; o != nil && !sdom.isAncestorEq(o.header, b); o = o.outer { } @@ -335,7 +335,7 @@ func loopnestfor(f *Func) *loopnest { inner++ } - f.logStat("loopstats:", + f.LogStat("loopstats:", l.depth, "depth", x, "exits", inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks") } diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 17ef5e461a9849..4416fa2cf37698 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -515,7 +515,7 @@ func prove(f *Func) { // getBranch returns the range restrictions added by p // when reaching b. p is the immediate dominator of b. -func getBranch(sdom sparseTree, p *Block, b *Block) branch { +func getBranch(sdom SparseTree, p *Block, b *Block) branch { if p == nil || p.Kind != BlockIf { return unknown } diff --git a/src/cmd/compile/internal/ssa/redblack32.go b/src/cmd/compile/internal/ssa/redblack32.go new file mode 100644 index 00000000000000..ae1ec352e782cd --- /dev/null +++ b/src/cmd/compile/internal/ssa/redblack32.go @@ -0,0 +1,429 @@ +// 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 ssa + +import "fmt" + +const ( + rankLeaf rbrank = 1 + rankZero rbrank = 0 +) + +type rbrank int8 + +// RBTint32 is a red-black tree with data stored at internal nodes, +// following Tarjan, Data Structures and Network Algorithms, +// pp 48-52, using explicit rank instead of red and black. +// Deletion is not yet implemented because it is not yet needed. +// Extra operations glb, lub, glbEq, lubEq are provided for +// use in sparse lookup algorithms. +type RBTint32 struct { + root *node32 + // An extra-clever implementation will have special cases + // for small sets, but we are not extra-clever today. +} + +func (t *RBTint32) String() string { + if t.root == nil { + return "[]" + } + return "[" + t.root.String() + "]" +} + +func (t *node32) String() string { + s := "" + if t.left != nil { + s = t.left.String() + " " + } + s = s + fmt.Sprintf("k=%d,d=%v", t.key, t.data) + if t.right != nil { + s = s + " " + t.right.String() + } + return s +} + +type node32 struct { + // Standard conventions hold for left = smaller, right = larger + left, right, parent *node32 + data interface{} + key int32 + rank rbrank // From Tarjan pp 48-49: + // If x is a node with a parent, then x.rank <= x.parent.rank <= x.rank+1. + // If x is a node with a grandparent, then x.rank < x.parent.parent.rank. + // If x is an "external [null] node", then x.rank = 0 && x.parent.rank = 1. + // Any node with one or more null children should have rank = 1. +} + +// makeNode returns a new leaf node with the given key and nil data. +func (t *RBTint32) makeNode(key int32) *node32 { + return &node32{key: key, rank: rankLeaf} +} + +// IsEmpty reports whether t is empty. +func (t *RBTint32) IsEmpty() bool { + return t.root == nil +} + +// IsSingle reports whether t is a singleton (leaf). +func (t *RBTint32) IsSingle() bool { + return t.root != nil && t.root.isLeaf() +} + +// VisitInOrder applies f to the key and data pairs in t, +// with keys ordered from smallest to largest. +func (t *RBTint32) VisitInOrder(f func(int32, interface{})) { + if t.root == nil { + return + } + t.root.visitInOrder(f) +} + +func (n *node32) Data() interface{} { + if n == nil { + return nil + } + return n.data +} + +func (n *node32) keyAndData() (k int32, d interface{}) { + if n == nil { + k = 0 + d = nil + } else { + k = n.key + d = n.data + } + return +} + +func (n *node32) Rank() rbrank { + if n == nil { + return 0 + } + return n.rank +} + +// Find returns the data associated with key in the tree, or +// nil if key is not in the tree. +func (t *RBTint32) Find(key int32) interface{} { + return t.root.find(key).Data() +} + +// Insert adds key to the tree and associates key with data. +// If key was already in the tree, it updates the associated data. +// Insert returns the previous data associated with key, +// or nil if key was not present. +// Insert panics if data is nil. +func (t *RBTint32) Insert(key int32, data interface{}) interface{} { + if data == nil { + panic("Cannot insert nil data into tree") + } + n := t.root + var newroot *node32 + if n == nil { + n = t.makeNode(key) + newroot = n + } else { + newroot, n = n.insert(key, t) + } + r := n.data + n.data = data + t.root = newroot + return r +} + +// Min returns the minimum element of t and its associated data. +// If t is empty, then (0, nil) is returned. +func (t *RBTint32) Min() (k int32, d interface{}) { + return t.root.min().keyAndData() +} + +// Max returns the maximum element of t and its associated data. +// If t is empty, then (0, nil) is returned. +func (t *RBTint32) Max() (k int32, d interface{}) { + return t.root.max().keyAndData() +} + +// Glb returns the greatest-lower-bound-exclusive of x and its associated +// data. If x has no glb in the tree, then (0, nil) is returned. +func (t *RBTint32) Glb(x int32) (k int32, d interface{}) { + return t.root.glb(x, false).keyAndData() +} + +// GlbEq returns the greatest-lower-bound-inclusive of x and its associated +// data. If x has no glbEQ in the tree, then (0, nil) is returned. +func (t *RBTint32) GlbEq(x int32) (k int32, d interface{}) { + return t.root.glb(x, true).keyAndData() +} + +// Lub returns the least-upper-bound-exclusive of x and its associated +// data. If x has no lub in the tree, then (0, nil) is returned. +func (t *RBTint32) Lub(x int32) (k int32, d interface{}) { + return t.root.lub(x, false).keyAndData() +} + +// LubEq returns the least-upper-bound-inclusive of x and its associated +// data. If x has no lubEq in the tree, then (0, nil) is returned. +func (t *RBTint32) LubEq(x int32) (k int32, d interface{}) { + return t.root.lub(x, true).keyAndData() +} + +func (t *node32) isLeaf() bool { + return t.left == nil && t.right == nil +} + +func (t *node32) visitInOrder(f func(int32, interface{})) { + if t.left != nil { + t.left.visitInOrder(f) + } + f(t.key, t.data) + if t.right != nil { + t.right.visitInOrder(f) + } +} + +func (t *node32) maxChildRank() rbrank { + if t.left == nil { + if t.right == nil { + return rankZero + } + return t.right.rank + } + if t.right == nil { + return t.left.rank + } + if t.right.rank > t.left.rank { + return t.right.rank + } + return t.left.rank +} + +func (t *node32) minChildRank() rbrank { + if t.left == nil || t.right == nil { + return rankZero + } + if t.right.rank < t.left.rank { + return t.right.rank + } + return t.left.rank +} + +func (t *node32) find(key int32) *node32 { + for t != nil { + if key < t.key { + t = t.left + } else if key > t.key { + t = t.right + } else { + return t + } + } + return nil +} + +func (t *node32) min() *node32 { + if t == nil { + return t + } + for t.left != nil { + t = t.left + } + return t +} + +func (t *node32) max() *node32 { + if t == nil { + return t + } + for t.right != nil { + t = t.right + } + return t +} + +func (t *node32) glb(key int32, allow_eq bool) *node32 { + var best *node32 = nil + for t != nil { + if key <= t.key { + if key == t.key && allow_eq { + return t + } + // t is too big, glb is to left. + t = t.left + } else { + // t is a lower bound, record it and seek a better one. + best = t + t = t.right + } + } + return best +} + +func (t *node32) lub(key int32, allow_eq bool) *node32 { + var best *node32 = nil + for t != nil { + if key >= t.key { + if key == t.key && allow_eq { + return t + } + // t is too small, lub is to right. + t = t.right + } else { + // t is a upper bound, record it and seek a better one. + best = t + t = t.left + } + } + return best +} + +func (t *node32) insert(x int32, w *RBTint32) (newroot, newnode *node32) { + // defaults + newroot = t + newnode = t + if x == t.key { + return + } + if x < t.key { + if t.left == nil { + n := w.makeNode(x) + n.parent = t + t.left = n + newnode = n + return + } + var new_l *node32 + new_l, newnode = t.left.insert(x, w) + t.left = new_l + new_l.parent = t + newrank := 1 + new_l.maxChildRank() + if newrank > t.rank { + if newrank > 1+t.right.Rank() { // rotations required + if new_l.left.Rank() < new_l.right.Rank() { + // double rotation + t.left = new_l.rightToRoot() + } + newroot = t.leftToRoot() + return + } else { + t.rank = newrank + } + } + } else { // x > t.key + if t.right == nil { + n := w.makeNode(x) + n.parent = t + t.right = n + newnode = n + return + } + var new_r *node32 + new_r, newnode = t.right.insert(x, w) + t.right = new_r + new_r.parent = t + newrank := 1 + new_r.maxChildRank() + if newrank > t.rank { + if newrank > 1+t.left.Rank() { // rotations required + if new_r.right.Rank() < new_r.left.Rank() { + // double rotation + t.right = new_r.leftToRoot() + } + newroot = t.rightToRoot() + return + } else { + t.rank = newrank + } + } + } + return +} + +func (t *node32) rightToRoot() *node32 { + // this + // left right + // rl rr + // + // becomes + // + // right + // this rr + // left rl + // + right := t.right + rl := right.left + right.parent = t.parent + right.left = t + t.parent = right + // parent's child ptr fixed in caller + t.right = rl + if rl != nil { + rl.parent = t + } + return right +} + +func (t *node32) leftToRoot() *node32 { + // this + // left right + // ll lr + // + // becomes + // + // left + // ll this + // lr right + // + left := t.left + lr := left.right + left.parent = t.parent + left.right = t + t.parent = left + // parent's child ptr fixed in caller + t.left = lr + if lr != nil { + lr.parent = t + } + return left +} + +// next returns the successor of t in a left-to-right +// walk of the tree in which t is embedded. +func (t *node32) next() *node32 { + // If there is a right child, it is to the right + r := t.right + if r != nil { + return r.min() + } + // if t is p.left, then p, else repeat. + p := t.parent + for p != nil { + if p.left == t { + return p + } + t = p + p = t.parent + } + return nil +} + +// prev returns the predecessor of t in a left-to-right +// walk of the tree in which t is embedded. +func (t *node32) prev() *node32 { + // If there is a left child, it is to the left + l := t.left + if l != nil { + return l.max() + } + // if t is p.right, then p, else repeat. + p := t.parent + for p != nil { + if p.right == t { + return p + } + t = p + p = t.parent + } + return nil +} diff --git a/src/cmd/compile/internal/ssa/redblack32_test.go b/src/cmd/compile/internal/ssa/redblack32_test.go new file mode 100644 index 00000000000000..6d72a3eee5f800 --- /dev/null +++ b/src/cmd/compile/internal/ssa/redblack32_test.go @@ -0,0 +1,276 @@ +// 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 ssa + +import ( + "fmt" + "testing" +) + +type sstring string + +func (s sstring) String() string { + return string(s) +} + +// wellFormed ensures that a red-black tree meets +// all of its invariants and returns a string identifying +// the first problem encountered. If there is no problem +// then the returned string is empty. The size is also +// returned to allow comparison of calculated tree size +// with expected. +func (t *RBTint32) wellFormed() (s string, i int) { + if t.root == nil { + s = "" + i = 0 + return + } + return t.root.wellFormedSubtree(nil, -0x80000000, 0x7fffffff) +} + +// wellFormedSubtree ensures that a red-black subtree meets +// all of its invariants and returns a string identifying +// the first problem encountered. If there is no problem +// then the returned string is empty. The size is also +// returned to allow comparison of calculated tree size +// with expected. +func (t *node32) wellFormedSubtree(parent *node32, min, max int32) (s string, i int) { + i = -1 // initialize to a failing value + s = "" // s is the reason for failure; empty means okay. + + if t.parent != parent { + s = "t.parent != parent" + return + } + + if min >= t.key { + s = "min >= t.key" + return + } + + if max <= t.key { + s = "max <= t.key" + return + } + + l := t.left + r := t.right + if l == nil && r == nil { + if t.rank != rankLeaf { + s = "leaf rank wrong" + return + } + } + if l != nil { + if t.rank < l.rank { + s = "t.rank < l.rank" + } else if t.rank > 1+l.rank { + s = "t.rank > 1+l.rank" + } else if t.rank <= l.maxChildRank() { + s = "t.rank <= l.maxChildRank()" + } else if t.key <= l.key { + s = "t.key <= l.key" + } + if s != "" { + return + } + } else { + if t.rank != 1 { + s = "t w/ left nil has rank != 1" + return + } + } + if r != nil { + if t.rank < r.rank { + s = "t.rank < r.rank" + } else if t.rank > 1+r.rank { + s = "t.rank > 1+r.rank" + } else if t.rank <= r.maxChildRank() { + s = "t.rank <= r.maxChildRank()" + } else if t.key >= r.key { + s = "t.key >= r.key" + } + if s != "" { + return + } + } else { + if t.rank != 1 { + s = "t w/ right nil has rank != 1" + return + } + } + ii := 1 + if l != nil { + res, il := l.wellFormedSubtree(t, min, t.key) + if res != "" { + s = "L." + res + return + } + ii += il + } + if r != nil { + res, ir := r.wellFormedSubtree(t, t.key, max) + if res != "" { + s = "R." + res + return + } + ii += ir + } + i = ii + return +} + +func (t *RBTint32) DebugString() string { + if t.root == nil { + return "" + } + return t.root.DebugString() +} + +// DebugString prints the tree with nested information +// to allow an eyeball check on the tree balance. +func (t *node32) DebugString() string { + s := "" + if t.left != nil { + s = s + "[" + s = s + t.left.DebugString() + s = s + "]" + } + s = s + fmt.Sprintf("%v=%v:%d", t.key, t.data, t.rank) + if t.right != nil { + s = s + "[" + s = s + t.right.DebugString() + s = s + "]" + } + return s +} + +func allRBT32Ops(te *testing.T, x []int32) { + t := &RBTint32{} + for i, d := range x { + x[i] = d + d // Double everything for glb/lub testing + } + + // fmt.Printf("Inserting double of %v", x) + k := 0 + min := int32(0x7fffffff) + max := int32(-0x80000000) + for _, d := range x { + if d < min { + min = d + } + + if d > max { + max = d + } + + t.Insert(d, sstring(fmt.Sprintf("%v", d))) + k++ + s, i := t.wellFormed() + if i != k { + te.Errorf("Wrong tree size %v, expected %v for %v", i, k, t.DebugString()) + } + if s != "" { + te.Errorf("Tree consistency problem at %v", s) + return + } else { + // fmt.Printf("%s", t.DebugString()) + } + } + + oops := false + + for _, d := range x { + s := fmt.Sprintf("%v", d) + f := t.Find(d) + + // data + if s != fmt.Sprintf("%v", f) { + te.Errorf("s(%v) != f(%v)", s, f) + oops = true + } + } + + if !oops { + for _, d := range x { + s := fmt.Sprintf("%v", d) + + kg, g := t.Glb(d + 1) + kge, ge := t.GlbEq(d) + kl, l := t.Lub(d - 1) + kle, le := t.LubEq(d) + + // keys + if d != kg { + te.Errorf("d(%v) != kg(%v)", d, kg) + } + if d != kl { + te.Errorf("d(%v) != kl(%v)", d, kl) + } + if d != kge { + te.Errorf("d(%v) != kge(%v)", d, kge) + } + if d != kle { + te.Errorf("d(%v) != kle(%v)", d, kle) + } + // data + if s != fmt.Sprintf("%v", g) { + te.Errorf("s(%v) != g(%v)", s, g) + } + if s != fmt.Sprintf("%v", l) { + te.Errorf("s(%v) != l(%v)", s, l) + } + if s != fmt.Sprintf("%v", ge) { + te.Errorf("s(%v) != ge(%v)", s, ge) + } + if s != fmt.Sprintf("%v", le) { + te.Errorf("s(%v) != le(%v)", s, le) + } + } + + for _, d := range x { + s := fmt.Sprintf("%v", d) + kge, ge := t.GlbEq(d + 1) + kle, le := t.LubEq(d - 1) + if d != kge { + te.Errorf("d(%v) != kge(%v)", d, kge) + } + if d != kle { + te.Errorf("d(%v) != kle(%v)", d, kle) + } + if s != fmt.Sprintf("%v", ge) { + te.Errorf("s(%v) != ge(%v)", s, ge) + } + if s != fmt.Sprintf("%v", le) { + te.Errorf("s(%v) != le(%v)", s, le) + } + } + + kg, g := t.Glb(min) + kge, ge := t.GlbEq(min - 1) + kl, l := t.Lub(max) + kle, le := t.LubEq(max + 1) + fmin := t.Find(min - 1) + fmax := t.Find(min + 11) + + if kg != 0 || kge != 0 || kl != 0 || kle != 0 { + te.Errorf("Got non-zero-key for missing query") + } + + if g != nil || ge != nil || l != nil || le != nil || fmin != nil || fmax != nil { + te.Errorf("Got non-error-data for missing query") + } + + } +} + +func TestAllRBTreeOps(t *testing.T) { + allRBT32Ops(t, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}) + allRBT32Ops(t, []int32{22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 3, 2, 1, 25, 24, 23, 12, 11, 10, 9, 8, 7, 6, 5, 4}) + allRBT32Ops(t, []int32{25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) + allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}) + allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2}) + allRBT32Ops(t, []int32{24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25}) +} diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 6c391aba2994bc..c9ef0d30174a04 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1529,7 +1529,7 @@ sinking: } if f.pass.stats > 0 { - f.logStat("spills_info", + f.LogStat("spills_info", nSpills, "spills", nSpillsInner, "inner_spills_remaining", nSpillsSunk, "inner_spills_sunk", nSpillsSunkUnused, "inner_spills_unused", nSpillsNotSunkLateUse, "inner_spills_shuffled", nSpillsChanged, "inner_spills_changed") } } diff --git a/src/cmd/compile/internal/ssa/sparsetree.go b/src/cmd/compile/internal/ssa/sparsetree.go index 45c78974963cdf..21fe68601eab3f 100644 --- a/src/cmd/compile/internal/ssa/sparsetree.go +++ b/src/cmd/compile/internal/ssa/sparsetree.go @@ -4,7 +4,9 @@ package ssa -type sparseTreeNode struct { +import "fmt" + +type SparseTreeNode struct { child *Block sibling *Block parent *Block @@ -20,26 +22,39 @@ type sparseTreeNode struct { entry, exit int32 } +func (s *SparseTreeNode) String() string { + return fmt.Sprintf("[%d,%d]", s.entry, s.exit) +} + +func (s *SparseTreeNode) Entry() int32 { + return s.entry +} + +func (s *SparseTreeNode) Exit() int32 { + return s.exit +} + const ( // When used to lookup up definitions in a sparse tree, // these adjustments to a block's entry (+adjust) and // exit (-adjust) numbers allow a distinction to be made // between assignments (typically branch-dependent - // conditionals) occurring "before" phi functions, the - // phi functions, and at the bottom of a block. - ADJUST_BEFORE = -1 // defined before phi - ADJUST_TOP = 0 // defined by phi - ADJUST_BOTTOM = 1 // defined within block + // conditionals) occurring "before" the block (e.g., as inputs + // to the block and its phi functions), "within" the block, + // and "after" the block. + AdjustBefore = -1 // defined before phi + AdjustWithin = 0 // defined by phi + AdjustAfter = 1 // defined within block ) -// A sparseTree is a tree of Blocks. +// A SparseTree is a tree of Blocks. // It allows rapid ancestor queries, // such as whether one block dominates another. -type sparseTree []sparseTreeNode +type SparseTree []SparseTreeNode -// newSparseTree creates a sparseTree from a block-to-parent map (array indexed by Block.ID) -func newSparseTree(f *Func, parentOf []*Block) sparseTree { - t := make(sparseTree, f.NumBlocks()) +// newSparseTree creates a SparseTree from a block-to-parent map (array indexed by Block.ID) +func newSparseTree(f *Func, parentOf []*Block) SparseTree { + t := make(SparseTree, f.NumBlocks()) for _, b := range f.Blocks { n := &t[b.ID] if p := parentOf[b.ID]; p != nil { @@ -80,7 +95,7 @@ func newSparseTree(f *Func, parentOf []*Block) sparseTree { // root left left right right root // 1 2e 3 | 4 5e 6 | 7 8x 9 | 10 11e 12 | 13 14x 15 | 16 17x 18 -func (t sparseTree) numberBlock(b *Block, n int32) int32 { +func (t SparseTree) numberBlock(b *Block, n int32) int32 { // reserve n for entry-1, assign n+1 to entry n++ t[b.ID].entry = n @@ -103,19 +118,19 @@ func (t sparseTree) numberBlock(b *Block, n int32) int32 { // to assign entry and exit numbers in the treewalk, those // numbers are also consistent with this order (i.e., // Sibling(x) has entry number larger than x's exit number). -func (t sparseTree) Sibling(x *Block) *Block { +func (t SparseTree) Sibling(x *Block) *Block { return t[x.ID].sibling } // Child returns a child of x in the dominator tree, or // nil if there are none. The choice of first child is // arbitrary but repeatable. -func (t sparseTree) Child(x *Block) *Block { +func (t SparseTree) Child(x *Block) *Block { return t[x.ID].child } // isAncestorEq reports whether x is an ancestor of or equal to y. -func (t sparseTree) isAncestorEq(x, y *Block) bool { +func (t SparseTree) isAncestorEq(x, y *Block) bool { if x == y { return true } @@ -125,7 +140,7 @@ func (t sparseTree) isAncestorEq(x, y *Block) bool { } // isAncestor reports whether x is a strict ancestor of y. -func (t sparseTree) isAncestor(x, y *Block) bool { +func (t SparseTree) isAncestor(x, y *Block) bool { if x == y { return false } @@ -136,6 +151,6 @@ func (t sparseTree) isAncestor(x, y *Block) bool { // maxdomorder returns a value to allow a maximal dominator first sort. maxdomorder(x) < maxdomorder(y) is true // if x may dominate y, and false if x cannot dominate y. -func (t sparseTree) maxdomorder(x *Block) int32 { +func (t SparseTree) maxdomorder(x *Block) int32 { return t[x.ID].entry } diff --git a/src/cmd/compile/internal/ssa/sparsetreemap.go b/src/cmd/compile/internal/ssa/sparsetreemap.go new file mode 100644 index 00000000000000..61276985b114bb --- /dev/null +++ b/src/cmd/compile/internal/ssa/sparsetreemap.go @@ -0,0 +1,169 @@ +// 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 ssa + +import "fmt" + +// A SparseTreeMap encodes a subset of nodes within a tree +// used for sparse-ancestor queries. +// +// Combined with a SparseTreeHelper, this supports an Insert +// to add a tree node to the set and a Find operation to locate +// the nearest tree ancestor of a given node such that the +// ancestor is also in the set. +// +// Given a set of blocks {B1, B2, B3} within the dominator tree, established by +// stm.Insert()ing B1, B2, B3, etc, a query at block B +// (performed with stm.Find(stm, B, adjust, helper)) +// will return the member of the set that is the nearest strict +// ancestor of B within the dominator tree, or nil if none exists. +// The expected complexity of this operation is the log of the size +// the set, given certain assumptions about sparsity (the log complexity +// could be guaranteed with additional data structures whose constant- +// factor overhead has not yet been justified.) +// +// The adjust parameter allows positioning of the insertion +// and lookup points within a block -- one of +// AdjustBefore, AdjustWithin, AdjustAfter, +// where lookups at AdjustWithin can find insertions at +// AdjustBefore in the same block, and lookups at AdjustAfter +// can find insertions at either AdjustBefore or AdjustWithin +// in the same block. (Note that this assumes a gappy numbering +// such that exit number or exit number is separated from its +// nearest neighbor by at least 3). +// +// The Sparse Tree lookup algorithm is described by +// Paul F. Dietz. Maintaining order in a linked list. In +// Proceedings of the Fourteenth Annual ACM Symposium on +// Theory of Computing, pages 122–127, May 1982. +// and by +// Ben Wegbreit. Faster retrieval from context trees. +// Communications of the ACM, 19(9):526–529, September 1976. +type SparseTreeMap RBTint32 + +// A SparseTreeHelper contains indexing and allocation data +// structures common to a collection of SparseTreeMaps, as well +// as exposing some useful control-flow-related data to other +// packages, such as gc. +type SparseTreeHelper struct { + Sdom []SparseTreeNode // indexed by block.ID + Po []*Block // exported data + Dom []*Block // exported data + Ponums []int32 // exported data +} + +// NewSparseTreeHelper returns a SparseTreeHelper for use +// in the gc package, for example in phi-function placement. +func NewSparseTreeHelper(f *Func) *SparseTreeHelper { + dom := dominators(f) + ponums := make([]int32, f.NumBlocks()) + po := postorderWithNumbering(f, ponums) + return makeSparseTreeHelper(newSparseTree(f, dom), dom, po, ponums) +} + +func (h *SparseTreeHelper) NewTree() *SparseTreeMap { + return &SparseTreeMap{} +} + +func makeSparseTreeHelper(sdom SparseTree, dom, po []*Block, ponums []int32) *SparseTreeHelper { + helper := &SparseTreeHelper{Sdom: []SparseTreeNode(sdom), + Dom: dom, + Po: po, + Ponums: ponums, + } + return helper +} + +// A sparseTreeMapEntry contains the data stored in a binary search +// data structure indexed by (dominator tree walk) entry and exit numbers. +// Each entry is added twice, once keyed by entry-1/entry/entry+1 and +// once keyed by exit+1/exit/exit-1. (there are three choices of paired indices, not 9, and they properly nest) +type sparseTreeMapEntry struct { + index *SparseTreeNode + block *Block // TODO: store this in a separate index. + data interface{} +} + +// Insert creates a definition within b with data x. +// adjust indicates where in the block should be inserted: +// AdjustBefore means defined at a phi function (visible Within or After in the same block) +// AdjustWithin means defined within the block (visible After in the same block) +// AdjustAfter means after the block (visible within child blocks) +func (m *SparseTreeMap) Insert(b *Block, adjust int32, x interface{}, helper *SparseTreeHelper) { + rbtree := (*RBTint32)(m) + blockIndex := &helper.Sdom[b.ID] + if blockIndex.entry == 0 { + // assert unreachable + return + } + entry := &sparseTreeMapEntry{index: blockIndex, data: x} + right := blockIndex.exit - adjust + _ = rbtree.Insert(right, entry) + + left := blockIndex.entry + adjust + _ = rbtree.Insert(left, entry) +} + +// Find returns the definition visible from block b, or nil if none can be found. +// Adjust indicates where the block should be searched. +// AdjustBefore searches before the phi functions of b. +// AdjustWithin searches starting at the phi functions of b. +// AdjustAfter searches starting at the exit from the block, including normal within-block definitions. +// +// Note that Finds are properly nested with Inserts: +// m.Insert(b, a) followed by m.Find(b, a) will not return the result of the insert, +// but m.Insert(b, AdjustBefore) followed by m.Find(b, AdjustWithin) will. +// +// Another way to think of this is that Find searches for inputs, Insert defines outputs. +func (m *SparseTreeMap) Find(b *Block, adjust int32, helper *SparseTreeHelper) interface{} { + rbtree := (*RBTint32)(m) + if rbtree == nil { + return nil + } + blockIndex := &helper.Sdom[b.ID] + _, v := rbtree.Glb(blockIndex.entry + adjust) + for v != nil { + otherEntry := v.(*sparseTreeMapEntry) + otherIndex := otherEntry.index + // Two cases -- either otherIndex brackets blockIndex, + // or it doesn't. + // + // Note that if otherIndex and blockIndex are + // the same block, then the glb test only passed + // because the definition is "before", + // i.e., k == blockIndex.entry-1 + // allowing equality is okay on the blocks check. + if otherIndex.exit >= blockIndex.exit { + // bracketed. + return otherEntry.data + } + // In the not-bracketed case, we could memoize the results of + // walking up the tree, but for now we won't. + // Memoize plan is to take the gap (inclusive) + // from otherIndex.exit+1 to blockIndex.entry-1 + // and insert it into this or a second tree. + // Said tree would then need adjusting whenever + // an insertion occurred. + + // Expectation is that per-variable tree is sparse, + // therefore probe siblings instead of climbing up. + // Note that each sibling encountered in this walk + // to find a defining ancestor shares that ancestor + // because the walk skips over the interior -- each + // Glb will be an exit, and the iteration is to the + // Glb of the entry. + _, v = rbtree.Glb(otherIndex.entry - 1) + } + return nil // nothing found +} + +func (m *SparseTreeMap) String() string { + tree := (*RBTint32)(m) + return tree.String() +} + +func (e *sparseTreeMapEntry) String() string { + return fmt.Sprintf("index=%v, data=%v", e.index, e.data) +} diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index c08ed79cd65fe9..83f65d093b7c5c 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -84,7 +84,7 @@ func stackalloc(f *Func, spillLive [][]ID) [][]ID { s.stackalloc() if f.pass.stats > 0 { - f.logStat("stack_alloc_stats", + f.LogStat("stack_alloc_stats", s.nArgSlot, "arg_slots", s.nNotNeed, "slot_not_needed", s.nNamedSlot, "named_slots", s.nAuto, "auto_slots", s.nReuse, "reused_slots", s.nSelfInterfere, "self_interfering") From 1b86862d0d6eeb818bc622fee5f140951bd31063 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 16 May 2016 13:13:25 -0700 Subject: [PATCH 116/267] doc: fix broken link to the vet command documentation Fixes #15188 Change-Id: I0ab7791f7db499cef6bc52292d3d93ff4da7caff Reviewed-on: https://go-review.googlesource.com/23151 Reviewed-by: Brad Fitzpatrick --- doc/cmd.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cmd.html b/doc/cmd.html index 5d20d3887ae96c..992f176014e234 100644 --- a/doc/cmd.html +++ b/doc/cmd.html @@ -89,7 +89,7 @@ -vet +vet      Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string. From c1b32acefb3b1438981ba9dc4f5259999e9fc2ab Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 16 May 2016 14:11:01 -0700 Subject: [PATCH 117/267] runtime: yield after raising signal that should kill process Issue #15613 points out that the darwin builders have been getting regular failures in which a process that should exit with a SIGPIPE signal is instead exiting with exit status 2. The code calls runtime.raise. On most systems runtime.raise is the equivalent of pthread_kill(gettid(), sig); that is, it kills the thread with the signal, which should ensure that the program does not keep going. On darwin, however, runtime.raise is actually kill(getpid(), sig); that is, it sends a signal to the entire process. If the process decides to deliver the signal to a different thread, then it is possible that in some cases the thread that calls raise is able to execute the next system call before the signal is actually delivered. That would cause the observed error. I have not been able to recreate the problem myself, so I don't know whether this actually fixes it. But, optimistically: Fixed #15613. Change-Id: I60c0a9912aae2f46143ca1388fd85e9c3fa9df1f Reviewed-on: https://go-review.googlesource.com/23152 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/signal1_unix.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go index 31c1f2c4e58e93..5080202833e3d8 100644 --- a/src/runtime/signal1_unix.go +++ b/src/runtime/signal1_unix.go @@ -193,7 +193,17 @@ func dieFromSignal(sig int32) { setsig(sig, _SIG_DFL, false) updatesigmask(sigmask{}) raise(sig) - // That should have killed us; call exit just in case. + + // That should have killed us. On some systems, though, raise + // sends the signal to the whole process rather than to just + // the current thread, which means that the signal may not yet + // have been delivered. Give other threads a chance to run and + // pick up the signal. + osyield() + osyield() + osyield() + + // If we are still somehow running, just exit with the wrong status. exit(2) } From 99ef42fe7b310749d83f9b76d814e78fe8139b42 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 16 May 2016 15:45:18 -0700 Subject: [PATCH 118/267] A+C: add Andrew Werner (corporate CLA for Upthere, Inc) Change-Id: I7627e480d5d2366cba223fd81635c4115649f752 Reviewed-on: https://go-review.googlesource.com/23154 Reviewed-by: Ian Lance Taylor --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 34a78e5bd08635..39098fca93d80a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -634,6 +634,7 @@ Tyler Treat Ugorji Nwoke Ulf Holm Nielsen Ulrich Kunitz +Upthere, Inc. Uriel Mangado Vadim Vygonets Vincent Ambo diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e225afec80c6ee..bffcb3c7f4562a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -98,6 +98,7 @@ Andrew Pritchard Andrew Radev Andrew Skiba Andrew Szeto +Andrew Werner Andrew Wilkins Andrew Williams Andrey Mirtchovski From 28c201860e0838b10972e805582007f9eb61e7ac Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Mon, 7 Dec 2015 16:36:11 +0000 Subject: [PATCH 119/267] mime/multipart: sort header keys to ensure reproducible output Adds a transparent sort to the mime/multipart package, which is only used in the CreatePart func. This will ensure the ordering of the MIMEHeader. The point of this change was to ensure the output would be consistent and something that could be depended on. Fixes #13522 Change-Id: I9584ef9dbe98ce97d536d897326914653f8d9ddf Reviewed-on: https://go-review.googlesource.com/17497 Reviewed-by: Brad Fitzpatrick --- src/mime/multipart/writer.go | 13 +++++++++---- src/mime/multipart/writer_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go index 80960939d62ecb..f82756d55185e2 100644 --- a/src/mime/multipart/writer.go +++ b/src/mime/multipart/writer.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "net/textproto" + "sort" "strings" ) @@ -94,10 +95,14 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { } else { fmt.Fprintf(&b, "--%s\r\n", w.boundary) } - // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort - // and clean, like http.Header.Write(w) does. - for k, vv := range header { - for _, v := range vv { + + keys := make([]string, 0, len(header)) + for k := range header { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + for _, v := range header[k] { fmt.Fprintf(&b, "%s: %s\r\n", k, v) } } diff --git a/src/mime/multipart/writer_test.go b/src/mime/multipart/writer_test.go index ba00c97eceea4b..9670c660a4a0b7 100644 --- a/src/mime/multipart/writer_test.go +++ b/src/mime/multipart/writer_test.go @@ -7,6 +7,7 @@ package multipart import ( "bytes" "io/ioutil" + "net/textproto" "strings" "testing" ) @@ -126,3 +127,32 @@ func TestWriterBoundaryGoroutines(t *testing.T) { w.Boundary() <-done } + +func TestSortedHeader(t *testing.T) { + var buf bytes.Buffer + w := NewWriter(&buf) + if err := w.SetBoundary("MIMEBOUNDARY"); err != nil { + t.Fatalf("Error setting mime boundary: %v", err) + } + + header := textproto.MIMEHeader{ + "A": {"2"}, + "B": {"5", "7", "6"}, + "C": {"4"}, + "M": {"3"}, + "Z": {"1"}, + } + + part, err := w.CreatePart(header) + if err != nil { + t.Fatalf("Unable to create part: %v", err) + } + part.Write([]byte("foo")) + + w.Close() + + want := "--MIMEBOUNDARY\r\nA: 2\r\nB: 5\r\nB: 7\r\nB: 6\r\nC: 4\r\nM: 3\r\nZ: 1\r\n\r\nfoo\r\n--MIMEBOUNDARY--\r\n" + if want != buf.String() { + t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want) + } +} From ccdca832c569727f7985966a3324421a69739f57 Mon Sep 17 00:00:00 2001 From: andrew werner Date: Tue, 15 Dec 2015 14:42:28 -0800 Subject: [PATCH 120/267] io: make chained multiReader Read more efficient before this change, when io.MultiReader was called many times but contain few underlying readers, calls to Read were unnecessarily expensive. Fixes #13558 Change-Id: I3ec4e88c7b50c075b148331fb1b7348a5840adbe Reviewed-on: https://go-review.googlesource.com/17873 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/io/multi.go | 7 +++++++ src/io/multi_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/io/multi.go b/src/io/multi.go index c23c12b151e132..ed05cac9e722d5 100644 --- a/src/io/multi.go +++ b/src/io/multi.go @@ -10,6 +10,13 @@ type multiReader struct { func (mr *multiReader) Read(p []byte) (n int, err error) { for len(mr.readers) > 0 { + // Optimization to flatten nested multiReaders (Issue 13558) + if len(mr.readers) == 1 { + if r, ok := mr.readers[0].(*multiReader); ok { + mr.readers = r.readers + continue + } + } n, err = mr.readers[0].Read(p) if n > 0 || err != EOF { if err == EOF { diff --git a/src/io/multi_test.go b/src/io/multi_test.go index 787ea341307a11..2dce36955ed260 100644 --- a/src/io/multi_test.go +++ b/src/io/multi_test.go @@ -7,9 +7,11 @@ package io_test import ( "bytes" "crypto/sha1" + "errors" "fmt" . "io" "io/ioutil" + "runtime" "strings" "testing" ) @@ -164,3 +166,33 @@ func TestMultiWriterCopy(t *testing.T) { t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world") } } + +// readerFunc is an io.Reader implemented by the underlying func. +type readerFunc func(p []byte) (int, error) + +func (f readerFunc) Read(p []byte) (int, error) { + return f(p) +} + +// Test that MultiReader properly flattens chained multiReaders when Read is called +func TestMultiReaderFlatten(t *testing.T) { + pc := make([]uintptr, 1000) // 1000 should fit the full stack + var myDepth = runtime.Callers(0, pc) + var readDepth int // will contain the depth from which fakeReader.Read was called + var r Reader = MultiReader(readerFunc(func(p []byte) (int, error) { + readDepth = runtime.Callers(1, pc) + return 0, errors.New("irrelevant") + })) + + // chain a bunch of multiReaders + for i := 0; i < 100; i++ { + r = MultiReader(r) + } + + r.Read(nil) // don't care about errors, just want to check the call-depth for Read + + if readDepth != myDepth+2 { // 2 should be multiReader.Read and fakeReader.Read + t.Errorf("multiReader did not flatten chained multiReaders: expected readDepth %d, got %d", + myDepth+2, readDepth) + } +} From 5ccd571f3e2798e4afe8affa354351b5055cb20d Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 16 May 2016 12:51:52 -0700 Subject: [PATCH 121/267] crypto/tls: document certificate chains in LoadX509KeyPair Fixes #15348 Change-Id: I9e0e1e3a26fa4cd697d2c613e6b4952188b7c7e1 Reviewed-on: https://go-review.googlesource.com/23150 Reviewed-by: Brad Fitzpatrick --- src/crypto/tls/tls.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go index 0be0b42912eeff..25dc386f53c8c9 100644 --- a/src/crypto/tls/tls.go +++ b/src/crypto/tls/tls.go @@ -170,10 +170,11 @@ func Dial(network, addr string, config *Config) (*Conn, error) { return DialWithDialer(new(net.Dialer), network, addr, config) } -// LoadX509KeyPair reads and parses a public/private key pair from a pair of -// files. The files must contain PEM encoded data. On successful return, -// Certificate.Leaf will be nil because the parsed form of the certificate is -// not retained. +// LoadX509KeyPair reads and parses a public/private key pair from a pair +// of files. The files must contain PEM encoded data. The certificate file +// may contain intermediate certificates following the leaf certificate to +// form a certificate chain. On successful return, Certificate.Leaf will +// be nil because the parsed form of the certificate is not retained. func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { certPEMBlock, err := ioutil.ReadFile(certFile) if err != nil { From ca831135b34d13fe5b774a6b23867dd1a277786a Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 17 May 2016 07:07:58 +0900 Subject: [PATCH 122/267] net: simplify interfaceTable for BSD variants This change drops parseInterfaceTable which becomes unnecessary by the golang.org/x/net/route plumbing. Change-Id: I05f96e347de950bb1e9292bb3eeff01bb40e292f Reviewed-on: https://go-review.googlesource.com/23125 Run-TryBot: Mikio Hara Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/net/interface_bsd.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 1ca2f36e772790..d791cb30167943 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -20,10 +20,6 @@ func interfaceTable(ifindex int) ([]Interface, error) { if err != nil { return nil, err } - return parseInterfaceTable(ifindex, msgs) -} - -func parseInterfaceTable(ifindex int, msgs []route.Message) ([]Interface, error) { n := len(msgs) if ifindex != 0 { n = 1 From 495e3c60aa61615dd603050ac47f86468f8222b6 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 17 May 2016 12:20:16 +0900 Subject: [PATCH 123/267] net: use IPv4/IPv6 reserved address blocks for documentation Also replaces google.com with golang.org in package documentation. Updates #15228. Change-Id: I554fa960878fa44557a522635ed412d8d7548d3f Reviewed-on: https://go-review.googlesource.com/23126 Reviewed-by: Brad Fitzpatrick --- src/net/dial.go | 8 ++++---- src/net/ip.go | 18 +++++++++--------- src/net/net.go | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/net/dial.go b/src/net/dial.go index 16f67a2f337427..55edb433953ae8 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -241,8 +241,8 @@ func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) ( // If the host is empty, as in ":80", the local system is assumed. // // Examples: -// Dial("tcp", "12.34.56.78:80") -// Dial("tcp", "google.com:http") +// Dial("tcp", "192.0.2.1:80") +// Dial("tcp", "golang.org:http") // Dial("tcp", "[2001:db8::1]:http") // Dial("tcp", "[fe80::1%lo0]:80") // Dial("tcp", ":80") @@ -252,8 +252,8 @@ func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) ( // literal IP address. // // Examples: -// Dial("ip4:1", "127.0.0.1") -// Dial("ip6:ospf", "::1") +// Dial("ip4:1", "192.0.2.1") +// Dial("ip6:ipv6-icmp", "2001:db8::1") // // For Unix networks, the address must be a file system path. func Dial(network, address string) (Conn, error) { diff --git a/src/net/ip.go b/src/net/ip.go index a2361bbdbfc132..06d349b5f2c3d0 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -255,7 +255,7 @@ func (ip IP) Mask(mask IPMask) IP { // It returns one of 4 forms: // - "", if ip has length 0 // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address -// - IPv6 ("2001:db9::1"), if ip is a valid IPv6 address +// - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address // - the hexadecimal form of ip, without punctuation, if no other cases apply func (ip IP) String() string { p := ip @@ -483,12 +483,12 @@ func (n *IPNet) Contains(ip IP) bool { // Network returns the address's network name, "ip+net". func (n *IPNet) Network() string { return "ip+net" } -// String returns the CIDR notation of n like "192.168.100.1/24" -// or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291. +// String returns the CIDR notation of n like "192.0.2.1/24" +// or "2001:db8::/48" as defined in RFC 4632 and RFC 4291. // If the mask is not in the canonical form, it returns the // string which consists of an IP address, followed by a slash // character and a mask expressed as hexadecimal form with no -// punctuation like "192.168.100.1/c000ff00". +// punctuation like "198.51.100.1/c000ff00". func (n *IPNet) String() string { nn, m := networkNumberAndMask(n) if nn == nil || m == nil { @@ -641,8 +641,8 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) { } // ParseIP parses s as an IP address, returning the result. -// The string s can be in dotted decimal ("74.125.19.99") -// or IPv6 ("2001:4860:0:2001::68") form. +// The string s can be in dotted decimal ("192.0.2.1") +// or IPv6 ("2001:db8::68") form. // If s is not a valid textual representation of an IP address, // ParseIP returns nil. func ParseIP(s string) IP { @@ -659,12 +659,12 @@ func ParseIP(s string) IP { } // ParseCIDR parses s as a CIDR notation IP address and mask, -// like "192.168.100.1/24" or "2001:DB8::/48", as defined in +// like "192.0.2.0/24" or "2001:db8::/32", as defined in // RFC 4632 and RFC 4291. // // It returns the IP address and the network implied by the IP -// and mask. For example, ParseCIDR("192.168.100.1/16") returns -// the IP address 192.168.100.1 and the network 192.168.0.0/16. +// and mask. For example, ParseCIDR("198.51.100.1/24") returns +// the IP address 198.51.100.1 and the network 198.51.100.0/24. func ParseCIDR(s string) (IP, *IPNet, error) { i := byteIndex(s, '/') if i < 0 { diff --git a/src/net/net.go b/src/net/net.go index 27e9ca367d4054..d6812d1ef054dc 100644 --- a/src/net/net.go +++ b/src/net/net.go @@ -14,7 +14,7 @@ the same interfaces and similar Dial and Listen functions. The Dial function connects to a server: - conn, err := net.Dial("tcp", "google.com:80") + conn, err := net.Dial("tcp", "golang.org:80") if err != nil { // handle error } From 1a3e4f05a067f37e8ee8f7a0d5eec39a7e0cad84 Mon Sep 17 00:00:00 2001 From: Konstantin Shaposhnikov Date: Tue, 17 May 2016 20:16:41 +0800 Subject: [PATCH 124/267] os/signal: fix wrong constant name in the documentation os.SIGINT is not defined, os.Interrupt or syscall.SIGINT should be used. Change-Id: I39867726d28e179d1160a4fd353b7bea676c9dbb Reviewed-on: https://go-review.googlesource.com/23127 Reviewed-by: Brad Fitzpatrick --- src/os/signal/doc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go index 9ee547b15db420..73b01a2764de60 100644 --- a/src/os/signal/doc.go +++ b/src/os/signal/doc.go @@ -205,8 +205,8 @@ before raising the signal. Windows On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause -the program to exit. If Notify is called for os.SIGINT, ^C or ^BREAK -will cause os.SIGINT to be sent on the channel, and the program will +the program to exit. If Notify is called for os.Interrupt, ^C or ^BREAK +will cause os.Interrupt to be sent on the channel, and the program will not exit. If Reset is called, or Stop is called on all channels passed to Notify, then the default behavior will be restored. From 9d36cac99c8248292be1cb6a196bbe0715d0c057 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 17 May 2016 13:09:11 -0700 Subject: [PATCH 125/267] reflect: remove out of date UTF-8 StructOf restriction The initial implementation of reflect.StructOf in https://golang.org/cl/9251 had a limitation that field names had to be ASCII, which was later lifted by https://golang.org/cl/21777. Remove the out-of-date documentation disallowing UTF-8 field names. Updates: #5748 Updates: #15064 Change-Id: I2c5bfea46bfd682449c6e847fc972a1a131f51b7 Reviewed-on: https://go-review.googlesource.com/23170 Reviewed-by: David Crawshaw --- src/reflect/type.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/reflect/type.go b/src/reflect/type.go index 3bfff4a7cc6aa0..dd7b797c048230 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2314,10 +2314,6 @@ type structTypeFixed32 struct { // StructOf returns the struct type containing fields. // The Offset and Index fields are ignored and computed as they would be // by the compiler. -// -// StructOf does not support creating structs with UTF-8 field names or -// UTF-8 (embedded) type names. -// This limitation may be lifted eventually. func StructOf(fields []StructField) Type { var ( hash = fnv1(0, []byte("struct {")...) From 7b597f4d92a844e30694095485c335baa93a1ad1 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 13 May 2016 05:02:00 +0900 Subject: [PATCH 126/267] net: deflake TestLookupPort for embedded, security-hardened platforms Fixes #14576. Change-Id: I760907c67c97cb827cf48ba7eb0bb2f4f8d4d790 Reviewed-on: https://go-review.googlesource.com/23111 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/net/error_test.go | 14 ++++++++++++++ src/net/lookup_test.go | 41 +++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/net/error_test.go b/src/net/error_test.go index 9f496d7d2db5e8..d6de5a3e68f048 100644 --- a/src/net/error_test.go +++ b/src/net/error_test.go @@ -762,3 +762,17 @@ func TestFileError(t *testing.T) { ln.Close() } } + +func parseLookupPortError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch nestedErr.(type) { + case *AddrError, *DNSError: + return nil + case *os.PathError: // for Plan 9 + return nil + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) +} diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 7dba393cee5c9e..1c417b6c9aefde 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -604,31 +604,16 @@ var lookupPortTests = []struct { port int ok bool }{ - {"tcp", "0", 0, true}, - {"tcp", "echo", 7, true}, - {"tcp", "discard", 9, true}, - {"tcp", "systat", 11, true}, - {"tcp", "daytime", 13, true}, - {"tcp", "chargen", 19, true}, - {"tcp", "ftp-data", 20, true}, - {"tcp", "ftp", 21, true}, - {"tcp", "telnet", 23, true}, - {"tcp", "smtp", 25, true}, - {"tcp", "time", 37, true}, - {"tcp", "domain", 53, true}, - {"tcp", "finger", 79, true}, - {"tcp", "42", 42, true}, + // See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml + // + // Please be careful about adding new mappings for testings. + // There are platforms having incomplete mappings for + // restricted resource access and security reasons. + {"tcp", "0", 0, true}, + {"tcp", "http", 80, true}, {"udp", "0", 0, true}, - {"udp", "echo", 7, true}, - {"udp", "tftp", 69, true}, - {"udp", "bootpc", 68, true}, - {"udp", "bootps", 67, true}, {"udp", "domain", 53, true}, - {"udp", "ntp", 123, true}, - {"udp", "snmp", 161, true}, - {"udp", "syslog", 514, true}, - {"udp", "42", 42, true}, {"--badnet--", "zzz", 0, false}, {"tcp", "--badport--", 0, false}, @@ -640,9 +625,11 @@ var lookupPortTests = []struct { // Issue 13610: LookupPort("tcp", "") {"tcp", "", 0, true}, - {"tcp6", "", 0, true}, {"tcp4", "", 0, true}, + {"tcp6", "", 0, true}, {"udp", "", 0, true}, + {"udp4", "", 0, true}, + {"udp6", "", 0, true}, } func TestLookupPort(t *testing.T) { @@ -656,8 +643,14 @@ func TestLookupPort(t *testing.T) { } for _, tt := range lookupPortTests { - if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok { + port, err := LookupPort(tt.network, tt.name) + if port != tt.port || (err == nil) != tt.ok { t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok) } + if err != nil { + if perr := parseLookupPortError(err); perr != nil { + t.Error(perr) + } + } } } From f744717d1924340b8f5e5a385e99078693ad9097 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Sat, 14 May 2016 07:54:02 +0200 Subject: [PATCH 127/267] debug/gosym: parse remote packages correctly Fixes #15675 Change-Id: I8bad220988e5d690f20804db970b2db037c81187 Reviewed-on: https://go-review.googlesource.com/23086 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/debug/gosym/symtab.go | 19 +++++++++++---- src/debug/gosym/symtab_test.go | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/debug/gosym/symtab_test.go diff --git a/src/debug/gosym/symtab.go b/src/debug/gosym/symtab.go index c8fa9a0b38417f..f5f99630950916 100644 --- a/src/debug/gosym/symtab.go +++ b/src/debug/gosym/symtab.go @@ -40,8 +40,13 @@ func (s *Sym) Static() bool { return s.Type >= 'a' } // PackageName returns the package part of the symbol name, // or the empty string if there is none. func (s *Sym) PackageName() string { - if i := strings.Index(s.Name, "."); i != -1 { - return s.Name[0:i] + pathend := strings.LastIndex(s.Name, "/") + if pathend < 0 { + pathend = 0 + } + + if i := strings.Index(s.Name[pathend:], "."); i != -1 { + return s.Name[:pathend+i] } return "" } @@ -49,12 +54,16 @@ func (s *Sym) PackageName() string { // ReceiverName returns the receiver type name of this symbol, // or the empty string if there is none. func (s *Sym) ReceiverName() string { - l := strings.Index(s.Name, ".") - r := strings.LastIndex(s.Name, ".") + pathend := strings.LastIndex(s.Name, "/") + if pathend < 0 { + pathend = 0 + } + l := strings.Index(s.Name[pathend:], ".") + r := strings.LastIndex(s.Name[pathend:], ".") if l == -1 || r == -1 || l == r { return "" } - return s.Name[l+1 : r] + return s.Name[pathend+l+1 : pathend+r] } // BaseName returns the symbol name without the package or receiver name. diff --git a/src/debug/gosym/symtab_test.go b/src/debug/gosym/symtab_test.go new file mode 100644 index 00000000000000..08e86336b8eb67 --- /dev/null +++ b/src/debug/gosym/symtab_test.go @@ -0,0 +1,43 @@ +// 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 gosym + +import ( + "fmt" + "testing" +) + +func assertString(t *testing.T, dsc, out, tgt string) { + if out != tgt { + t.Fatalf("Expected: %q Actual: %q for %s", tgt, out, dsc) + } +} + +func TestStandardLibPackage(t *testing.T) { + s1 := Sym{Name: "io.(*LimitedReader).Read"} + s2 := Sym{Name: "io.NewSectionReader"} + assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "io") + assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "io") + assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LimitedReader)") + assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "") +} + +func TestStandardLibPathPackage(t *testing.T) { + s1 := Sym{Name: "debug/gosym.(*LineTable).PCToLine"} + s2 := Sym{Name: "debug/gosym.NewTable"} + assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "debug/gosym") + assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "debug/gosym") + assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LineTable)") + assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "") +} + +func TestRemotePackage(t *testing.T) { + s1 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.(*FlagSet).PrintDefaults"} + s2 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.PrintDefaults"} + assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "github.com/docker/doc.ker/pkg/mflag") + assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "github.com/docker/doc.ker/pkg/mflag") + assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*FlagSet)") + assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "") +} From 733162fd6c0df8bd700859974957b25045fe9ee4 Mon Sep 17 00:00:00 2001 From: James Chacon Date: Fri, 6 May 2016 11:51:56 -0700 Subject: [PATCH 128/267] runtime: prevent racefini from being invoked more than once racefini calls __tsan_fini which is C code and at the end of it invoked the standard C library exit(3) call. This has undefined behavior if invoked more than once. Specifically in C++ programs it caused static destructors to run twice. At least on glibc impls it also means the at_exit handlers list (where those are stored) also free's a list entry when it completes these. So invoking twice results in a double free at exit which trips debug memory allocation tracking. Fix all of this by using an atomic as a boolean barrier around calls to racefini being invoked > 1 time. Fixes #15578 Change-Id: I49222aa9b8ded77160931f46434c61a8379570fc Reviewed-on: https://go-review.googlesource.com/22882 Reviewed-by: Dmitry Vyukov Run-TryBot: Dmitry Vyukov TryBot-Result: Gobot Gobot --- src/runtime/race.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/runtime/race.go b/src/runtime/race.go index ecd68d80ce5249..42da936ddbf695 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -283,8 +283,16 @@ func raceinit() (gctx, pctx uintptr) { return } +var raceFiniLock mutex + //go:nosplit func racefini() { + // racefini() can only be called once to avoid races. + // This eventually (via __tsan_fini) calls C.exit which has + // undefined behavior if called more than once. If the lock is + // already held it's assumed that the first caller exits the program + // so other calls can hang forever without an issue. + lock(&raceFiniLock) racecall(&__tsan_fini, 0, 0, 0, 0) } From f962e6e0e21b9e73981e6cf2407ea01fce04b989 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 00:35:43 +0000 Subject: [PATCH 129/267] net/http: add test confirming a connection reuse case Verify that for a server doing chunked encoding, with the final data and EOF arriving together, the client will reuse the connection even if it closes the body without seeing an EOF. The server sends at least one non-zero chunk and one zero chunk. This verifies that the client's bufio reading reads ahead and notes the EOF, so even if the JSON decoder doesn't read the EOF itself, as long as somebody sees it, a close won't forcible tear down the connection. This was true at least of https://golang.org/cl/21291 No code change. Test already passed (even with lots of runs, including in race mode with randomized goroutine scheduling). Updates #15703 Change-Id: I2140b3eec6b099b6b6e54f153fe271becac5d949 Reviewed-on: https://go-review.googlesource.com/23200 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Andrew Gerrand --- src/net/http/serve_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 95983e4b02e756..e398c92638eb24 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -11,6 +11,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/json" "errors" "fmt" "internal/testenv" @@ -792,6 +793,36 @@ func TestHTTP10KeepAlive304Response(t *testing.T) { HandlerFunc(send304)) } +// Issue 15703 +func TestKeepAliveFinalChunkWithEOF(t *testing.T) { + defer afterTest(t) + cst := newClientServerTest(t, false /* h1 */, HandlerFunc(func(w ResponseWriter, r *Request) { + w.(Flusher).Flush() // force chunked encoding + w.Write([]byte("{\"Addr\": \"" + r.RemoteAddr + "\"}")) + })) + defer cst.close() + type data struct { + Addr string + } + var addrs [2]data + for i := range addrs { + res, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + if err := json.NewDecoder(res.Body).Decode(&addrs[i]); err != nil { + t.Fatal(err) + } + if addrs[i].Addr == "" { + t.Fatal("no address") + } + res.Body.Close() + } + if addrs[0] != addrs[1] { + t.Fatalf("connection not reused") + } +} + func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) } func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) } From ac66bb343181bef154342638d45dcc2c695ded00 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 17 May 2016 20:22:48 -0600 Subject: [PATCH 130/267] crypto/x509: fix typo in docs for CreateCertificateRequest Update the doc for CreateCertificateRequest to state that it creates a `new certificate request` instead of just a `new certificate` Fixes #14649. Change-Id: Ibbbcf91d74168998990990e78e5272a6cf294d51 Reviewed-on: https://go-review.googlesource.com/23204 Reviewed-by: Russ Cox --- src/crypto/x509/x509.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 6004d5cd239d18..9e6d67df55fc94 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1853,8 +1853,8 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) return ret, nil } -// CreateCertificateRequest creates a new certificate based on a template. The -// following members of template are used: Subject, Attributes, +// CreateCertificateRequest creates a new certificate request based on a template. +// The following members of template are used: Subject, Attributes, // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. // The private key is the private key of the signer. // From 23a59ba17cbfeb5380845f309f88165b2e38930b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 17 May 2016 18:16:47 -0700 Subject: [PATCH 131/267] runtime: deflake TestSignalExitStatus The signal might get delivered to a different thread, and that thread might not run again before the currently running thread returns and exits. Sleep to give the other thread time to pick up the signal and crash. Not tested for all cases, but, optimistically: Fixes #14063. Change-Id: Iff58669ac6185ad91cce85e0e86f17497a3659fd Reviewed-on: https://go-review.googlesource.com/23203 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Mikio Hara --- src/runtime/crash_unix_test.go | 4 ---- src/runtime/testdata/testprog/signal.go | 14 +++++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 771b303f6ee39a..0a79661f1ead83 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -149,10 +149,6 @@ func loop(i int, c chan bool) { func TestSignalExitStatus(t *testing.T) { testenv.MustHaveGoBuild(t) - switch runtime.GOOS { - case "netbsd", "solaris": - t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS) - } exe, err := buildTestProg(t, "testprog") if err != nil { t.Fatal(err) diff --git a/src/runtime/testdata/testprog/signal.go b/src/runtime/testdata/testprog/signal.go index 7926908828ba85..2ccbada57b3c1a 100644 --- a/src/runtime/testdata/testprog/signal.go +++ b/src/runtime/testdata/testprog/signal.go @@ -6,7 +6,10 @@ package main -import "syscall" +import ( + "syscall" + "time" +) func init() { register("SignalExitStatus", SignalExitStatus) @@ -14,4 +17,13 @@ func init() { func SignalExitStatus() { syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + + // Should die immediately, but we've seen flakiness on various + // systems (see issue 14063). It's possible that the signal is + // being delivered to a different thread and we are returning + // and exiting before that thread runs again. Give the program + // a little while to die to make sure we pick up the signal + // before we return and exit the program. The time here + // shouldn't matter--we'll never really sleep this long. + time.Sleep(time.Second) } From cdcb8271a411bac78aa886a5998ac2c10b23f058 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 01:00:32 +0000 Subject: [PATCH 132/267] regexp/syntax: clarify that \Z means Perl's \Z Fixes #14793 Change-Id: I408056d096cd6a999fa5e349704b5ea8e26d2e4e Reviewed-on: https://go-review.googlesource.com/23201 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/regexp/syntax/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/regexp/syntax/doc.go b/src/regexp/syntax/doc.go index e6c2ce5940ac2e..efc0b435711f3c 100644 --- a/src/regexp/syntax/doc.go +++ b/src/regexp/syntax/doc.go @@ -66,7 +66,7 @@ Grouping: Empty strings: ^ at beginning of text or line (flag m=true) - $ at end of text (like \z not \Z) or line (flag m=true) + $ at end of text (like \z not Perl's \Z) or line (flag m=true) \A at beginning of text \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) \B not at ASCII word boundary From 6de34e6e25732757b7b40e4053c6ac7fb6d00df4 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 18 May 2016 10:54:20 +0900 Subject: [PATCH 133/267] net: deflake TestLookupPort on Android Looks like some version of Android still fails with "servname not supported for ai_socktype". It probably doesn't support ai_socktype=SOCK_STREAM. Updates #14576. Change-Id: I77ecff147d5b759e3281b3798c60f150a4aab811 Reviewed-on: https://go-review.googlesource.com/23194 Reviewed-by: Ian Lance Taylor --- src/net/lookup_test.go | 61 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 1c417b6c9aefde..7d18cbdced7f20 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -598,41 +598,40 @@ func srvString(srvs []*SRV) string { return buf.String() } -var lookupPortTests = []struct { - network string - name string - port int - ok bool -}{ +func TestLookupPort(t *testing.T) { // See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml // // Please be careful about adding new mappings for testings. // There are platforms having incomplete mappings for // restricted resource access and security reasons. + type test struct { + network string + name string + port int + ok bool + } + var tests = []test{ + {"tcp", "0", 0, true}, + {"udp", "0", 0, true}, + {"udp", "domain", 53, true}, + + {"--badnet--", "zzz", 0, false}, + {"tcp", "--badport--", 0, false}, + {"tcp", "-1", 0, false}, + {"tcp", "65536", 0, false}, + {"udp", "-1", 0, false}, + {"udp", "65536", 0, false}, + {"tcp", "123456789", 0, false}, + + // Issue 13610: LookupPort("tcp", "") + {"tcp", "", 0, true}, + {"tcp4", "", 0, true}, + {"tcp6", "", 0, true}, + {"udp", "", 0, true}, + {"udp4", "", 0, true}, + {"udp6", "", 0, true}, + } - {"tcp", "0", 0, true}, - {"tcp", "http", 80, true}, - {"udp", "0", 0, true}, - {"udp", "domain", 53, true}, - - {"--badnet--", "zzz", 0, false}, - {"tcp", "--badport--", 0, false}, - {"tcp", "-1", 0, false}, - {"tcp", "65536", 0, false}, - {"udp", "-1", 0, false}, - {"udp", "65536", 0, false}, - {"tcp", "123456789", 0, false}, - - // Issue 13610: LookupPort("tcp", "") - {"tcp", "", 0, true}, - {"tcp4", "", 0, true}, - {"tcp6", "", 0, true}, - {"udp", "", 0, true}, - {"udp4", "", 0, true}, - {"udp6", "", 0, true}, -} - -func TestLookupPort(t *testing.T) { switch runtime.GOOS { case "nacl": t.Skipf("not supported on %s", runtime.GOOS) @@ -640,9 +639,11 @@ func TestLookupPort(t *testing.T) { if netGo { t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS) } + default: + tests = append(tests, test{"tcp", "http", 80, true}) } - for _, tt := range lookupPortTests { + for _, tt := range tests { port, err := LookupPort(tt.network, tt.name) if port != tt.port || (err == nil) != tt.ok { t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok) From d4ed8da9969dd04a3b10683971185359e5ec5302 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 18 May 2016 13:02:39 +0900 Subject: [PATCH 134/267] net: don't increase test table rows when using -test.count flag Change-Id: I7881e3353dc5cd9755a79ea0eab146c6a0a08306 Reviewed-on: https://go-review.googlesource.com/23195 Run-TryBot: Mikio Hara Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/net/dial_test.go | 107 +++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index ead1e68d46f43e..93cffca93d2689 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -591,68 +591,67 @@ func TestDialerPartialDeadline(t *testing.T) { } } -type dialerLocalAddrTest struct { - network, raddr string - laddr Addr - error -} - -var dialerLocalAddrTests = []dialerLocalAddrTest{ - {"tcp4", "127.0.0.1", nil, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{}, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, - {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, - {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, - {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, - - {"tcp6", "::1", nil, nil}, - {"tcp6", "::1", &TCPAddr{}, nil}, - {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, - {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, - {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, - {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, - {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, - {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil}, - {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, - {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, - - {"tcp", "127.0.0.1", nil, nil}, - {"tcp", "127.0.0.1", &TCPAddr{}, nil}, - {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, - {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, - {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, - {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, - {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, - {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, - {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, - - {"tcp", "::1", nil, nil}, - {"tcp", "::1", &TCPAddr{}, nil}, - {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, - {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, - {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, - {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, - {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, - {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil}, - {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, - {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, -} - func TestDialerLocalAddr(t *testing.T) { if !supportsIPv4 || !supportsIPv6 { t.Skip("both IPv4 and IPv6 are required") } + type test struct { + network, raddr string + laddr Addr + error + } + var tests = []test{ + {"tcp4", "127.0.0.1", nil, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{}, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, + {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, + {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, + {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, + + {"tcp6", "::1", nil, nil}, + {"tcp6", "::1", &TCPAddr{}, nil}, + {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, + {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, + {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, + {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, + {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, + {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil}, + {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, + {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, + + {"tcp", "127.0.0.1", nil, nil}, + {"tcp", "127.0.0.1", &TCPAddr{}, nil}, + {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, + {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, + {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, + {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, + {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, + {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, + {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, + + {"tcp", "::1", nil, nil}, + {"tcp", "::1", &TCPAddr{}, nil}, + {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, + {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, + {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, + {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, + {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, + {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil}, + {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, + {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, + } + if supportsIPv4map { - dialerLocalAddrTests = append(dialerLocalAddrTests, dialerLocalAddrTest{ + tests = append(tests, test{ "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil, }) } else { - dialerLocalAddrTests = append(dialerLocalAddrTests, dialerLocalAddrTest{ + tests = append(tests, test{ "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}, }) } @@ -682,7 +681,7 @@ func TestDialerLocalAddr(t *testing.T) { } } - for _, tt := range dialerLocalAddrTests { + for _, tt := range tests { d := &Dialer{LocalAddr: tt.laddr} var addr string ip := ParseIP(tt.raddr) From c6a5b3602a87b2d1321ad11aa64b7f588bbb683b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 17 May 2016 18:07:07 -0700 Subject: [PATCH 135/267] doc/effective_go: clarify backward function reference Fixes #14656. Change-Id: I37a9aa51705ae18bd034f2cc6dbf06a55f969197 Reviewed-on: https://go-review.googlesource.com/23202 Reviewed-by: Rob Pike --- doc/effective_go.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index 4ea3fae31836e4..1e66c0c6145fae 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -2014,7 +2014,7 @@

Pointers vs. Values

type ByteSlice []byte func (slice ByteSlice) Append(data []byte) []byte { - // Body exactly the same as above + // Body exactly the same as the Append function defined above. }

From c65647d6204531e93c19ea2dba01ff13d1b8ef31 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 19 Apr 2016 15:02:06 -0700 Subject: [PATCH 136/267] cmd/compile: handle unsafe.Pointer(f()) correctly Previously statements like f(unsafe.Pointer(g()), int(h())) would be reordered into a sequence of statements like autotmp_g := g() autotmp_h := h() f(unsafe.Pointer(autotmp_g), int(autotmp_h)) which can leave g's temporary value on the stack as a uintptr, rather than an unsafe.Pointer. Instead, recognize uintptr-to-unsafe.Pointer conversions when reordering function calls to instead produce: autotmp_g := unsafe.Pointer(g()) autotmp_h := h() f(autotmp_g, int(autotmp_h)) Fixes #15329. Change-Id: I2cdbd89d233d0d5c94791513a9fd5fd958d11ed5 Reviewed-on: https://go-review.googlesource.com/22273 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall Reviewed-by: Russ Cox --- src/cmd/compile/internal/gc/order.go | 14 +++++ test/fixedbugs/issue15329.go | 79 ++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 test/fixedbugs/issue15329.go diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 7026ad79efa383..da334a1558cfd4 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -1082,6 +1082,20 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node { n.Left = orderaddrtemp(n.Left, order) } + case OCONVNOP: + if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) { + // When reordering unsafe.Pointer(f()) into a separate + // statement, the conversion and function call must stay + // together. See golang.org/issue/15329. + orderinit(n.Left, order) + ordercall(n.Left, order) + if lhs == nil || lhs.Op != ONAME || instrumenting { + n = ordercopyexpr(n, n.Type, order, 0) + } + } else { + n.Left = orderexpr(n.Left, order, nil) + } + case OANDAND, OOROR: mark := marktemp(order) n.Left = orderexpr(n.Left, order, nil) diff --git a/test/fixedbugs/issue15329.go b/test/fixedbugs/issue15329.go new file mode 100644 index 00000000000000..30fbf137970651 --- /dev/null +++ b/test/fixedbugs/issue15329.go @@ -0,0 +1,79 @@ +// run + +// 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. + +// Previously, cmd/compile would rewrite +// +// check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer())) +// +// to +// +// var autotmp_1 uintptr = testMeth(1).Pointer() +// var autotmp_2 uintptr = testMeth(2).Pointer() +// check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2)) +// +// However, that means autotmp_1 is the only reference to the int +// variable containing the value "1", but it's not a pointer type, +// so it was at risk of being garbage collected by the evaluation of +// testMeth(2).Pointer(), even though package unsafe's documentation +// says the original code was allowed. +// +// Now cmd/compile rewrites it to +// +// var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer()) +// var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer()) +// check(autotmp_1, autotmp_2) +// +// to ensure the pointed-to variables are visible to the GC. + +package main + +import ( + "fmt" + "reflect" + "runtime" + "unsafe" +) + +func main() { + // Test all the different ways we can invoke reflect.Value.Pointer. + + // Direct method invocation. + check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer())) + + // Invocation via method expression. + check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2)))) + + // Invocation via interface. + check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer())) + + // Invocation via method value. + check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)())) +} + +func check(p, q unsafe.Pointer) { + a, b := *(*int)(p), *(*int)(q) + if a != 1 || b != 2 { + fmt.Printf("got %v, %v; expected 1, 2\n", a, b) + } +} + +func testMeth(x int) reflect.Value { + // Force GC to run. + runtime.GC() + return reflect.ValueOf(&x) +} + +type Pointerer interface { + Pointer() uintptr +} + +func testInter(x int) Pointerer { + return testMeth(x) +} + +func testFunc(x int) func() uintptr { + return testMeth(x).Pointer +} From 2380a039c0457141e28f8f927139e1f9c38f8205 Mon Sep 17 00:00:00 2001 From: Cuihtlauac ALVARADO Date: Tue, 17 May 2016 09:27:00 +0200 Subject: [PATCH 137/267] runtime: in tests, make sure gdb does not start with a shell On some systems, gdb is set to: "startup-with-shell on". This breaks runtime_test. This just make sure gdb does not start by spawning a shell. Fixes #15354 Change-Id: Ia040931c61dea22f4fdd79665ab9f84835ecaa70 Reviewed-on: https://go-review.googlesource.com/23142 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/runtime-gdb_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 4f82646dbbe7f7..0ad88565148d2e 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -98,6 +98,7 @@ func TestGdbPython(t *testing.T) { args := []string{"-nx", "-q", "--batch", "-iex", fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()), + "-ex", "set startup-with-shell off", "-ex", "info auto-load python-scripts", "-ex", "br main.go:10", "-ex", "run", @@ -226,6 +227,7 @@ func TestGdbBacktrace(t *testing.T) { // Execute gdb commands. args := []string{"-nx", "-batch", + "-ex", "set startup-with-shell off", "-ex", "break main.eee", "-ex", "run", "-ex", "backtrace", From d35a4158ab66aef99d9204c65cc2e2fa74b57a73 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 9 May 2016 14:59:25 -0400 Subject: [PATCH 138/267] cmd/compile: reduce element size of arrays in sparse{map,set} sparseSet and sparseMap only need 32 bit integers in their arrays, since a sparseEntry key is also limited to 32 bits. This appears to reduce the space allocated for at least one pathological compilation by 1%, perhaps more. Not necessarily for 1.7, but it saves a little and is very low-risk. Change-Id: Icf1185859e9f5fe1261a206b441e02c34f7d02fd Reviewed-on: https://go-review.googlesource.com/22972 Run-TryBot: David Chase TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall Reviewed-by: Russ Cox --- src/cmd/compile/internal/ssa/sparsemap.go | 18 +++++++++--------- src/cmd/compile/internal/ssa/sparseset.go | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go index 0211a70f09d211..afb9f6049186cc 100644 --- a/src/cmd/compile/internal/ssa/sparsemap.go +++ b/src/cmd/compile/internal/ssa/sparsemap.go @@ -14,13 +14,13 @@ type sparseEntry struct { type sparseMap struct { dense []sparseEntry - sparse []int + sparse []int32 } // newSparseMap returns a sparseMap that can map // integers between 0 and n-1 to int32s. func newSparseMap(n int) *sparseMap { - return &sparseMap{nil, make([]int, n)} + return &sparseMap{dense: nil, sparse: make([]int32, n)} } func (s *sparseMap) size() int { @@ -29,14 +29,14 @@ func (s *sparseMap) size() int { func (s *sparseMap) contains(k ID) bool { i := s.sparse[k] - return i < len(s.dense) && s.dense[i].key == k + return i < int32(len(s.dense)) && s.dense[i].key == k } // get returns the value for key k, or -1 if k does // not appear in the map. func (s *sparseMap) get(k ID) int32 { i := s.sparse[k] - if i < len(s.dense) && s.dense[i].key == k { + if i < int32(len(s.dense)) && s.dense[i].key == k { return s.dense[i].val } return -1 @@ -44,12 +44,12 @@ func (s *sparseMap) get(k ID) int32 { func (s *sparseMap) set(k ID, v int32) { i := s.sparse[k] - if i < len(s.dense) && s.dense[i].key == k { + if i < int32(len(s.dense)) && s.dense[i].key == k { s.dense[i].val = v return } s.dense = append(s.dense, sparseEntry{k, v}) - s.sparse[k] = len(s.dense) - 1 + s.sparse[k] = int32(len(s.dense)) - 1 } // setBit sets the v'th bit of k's value, where 0 <= v < 32 @@ -58,17 +58,17 @@ func (s *sparseMap) setBit(k ID, v uint) { panic("bit index too large.") } i := s.sparse[k] - if i < len(s.dense) && s.dense[i].key == k { + if i < int32(len(s.dense)) && s.dense[i].key == k { s.dense[i].val |= 1 << v return } s.dense = append(s.dense, sparseEntry{k, 1 << v}) - s.sparse[k] = len(s.dense) - 1 + s.sparse[k] = int32(len(s.dense)) - 1 } func (s *sparseMap) remove(k ID) { i := s.sparse[k] - if i < len(s.dense) && s.dense[i].key == k { + if i < int32(len(s.dense)) && s.dense[i].key == k { y := s.dense[len(s.dense)-1] s.dense[i] = y s.sparse[y.key] = i diff --git a/src/cmd/compile/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go index 66bebf139e66bf..b5cabfb0cdf083 100644 --- a/src/cmd/compile/internal/ssa/sparseset.go +++ b/src/cmd/compile/internal/ssa/sparseset.go @@ -9,13 +9,13 @@ package ssa type sparseSet struct { dense []ID - sparse []int + sparse []int32 } // newSparseSet returns a sparseSet that can represent // integers between 0 and n-1 func newSparseSet(n int) *sparseSet { - return &sparseSet{nil, make([]int, n)} + return &sparseSet{dense: nil, sparse: make([]int32, n)} } func (s *sparseSet) cap() int { @@ -28,16 +28,16 @@ func (s *sparseSet) size() int { func (s *sparseSet) contains(x ID) bool { i := s.sparse[x] - return i < len(s.dense) && s.dense[i] == x + return i < int32(len(s.dense)) && s.dense[i] == x } func (s *sparseSet) add(x ID) { i := s.sparse[x] - if i < len(s.dense) && s.dense[i] == x { + if i < int32(len(s.dense)) && s.dense[i] == x { return } s.dense = append(s.dense, x) - s.sparse[x] = len(s.dense) - 1 + s.sparse[x] = int32(len(s.dense)) - 1 } func (s *sparseSet) addAll(a []ID) { @@ -54,7 +54,7 @@ func (s *sparseSet) addAllValues(a []*Value) { func (s *sparseSet) remove(x ID) { i := s.sparse[x] - if i < len(s.dense) && s.dense[i] == x { + if i < int32(len(s.dense)) && s.dense[i] == x { y := s.dense[len(s.dense)-1] s.dense[i] = y s.sparse[y] = i From 2ba8fc5b086942dbb23282702f61c813298867f3 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Tue, 17 May 2016 08:24:18 -0500 Subject: [PATCH 139/267] vcs: Add support for git.openstack.org Go is being proposed as an officially supported language for elements of OpenStack: https://review.openstack.org/#/c/312267/ As such, repos that exist in OpenStack's git infrastructure are likely to become places from which people might want to go get things. Allow optional .git suffixes to allow writing code that depends on git.openstack.org repos that will work with older go versions while we wait for this support to roll out. Change-Id: Ia64bdb1dafea33b1c3770803230d30ec1059df22 Reviewed-on: https://go-review.googlesource.com/23135 Reviewed-by: Russ Cox --- src/cmd/go/vcs.go | 9 +++++++++ src/cmd/go/vcs_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 4ff71f21683125..3b6e08f155b0e0 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -848,6 +848,15 @@ var vcsPaths = []*vcsPath{ repo: "https://{root}", }, + // Git at OpenStack + { + prefix: "git.openstack.org", + re: `^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + // General syntax for any server. // Must be last. { diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go index d9511894598704..06650608ba40a8 100644 --- a/src/cmd/go/vcs_test.go +++ b/src/cmd/go/vcs_test.go @@ -86,6 +86,39 @@ func TestRepoRootForImportPath(t *testing.T) { "hub.jazz.net/git/USER/pkgname", nil, }, + // OpenStack tests + { + "git.openstack.org/openstack/swift", + &repoRoot{ + vcs: vcsGit, + repo: "https://git.openstack.org/openstack/swift", + }, + }, + // Trailing .git is less preferred but included for + // compatibility purposes while the same source needs to + // be compilable on both old and new go + { + "git.openstack.org/openstack/swift.git", + &repoRoot{ + vcs: vcsGit, + repo: "https://git.openstack.org/openstack/swift", + }, + }, + { + "git.openstack.org/openstack/swift/go/hummingbird", + &repoRoot{ + vcs: vcsGit, + repo: "https://git.openstack.org/openstack/swift", + }, + }, + { + "git.openstack.org", + nil, + }, + { + "git.openstack.org/openstack", + nil, + }, // Spaces are not valid in package name { "git.apache.org/package name/path/to/lib", From b30fcbc9f59ca4bf1723eb6743b47fa89b3847a3 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 14 Apr 2016 13:52:56 -0700 Subject: [PATCH 140/267] crypto/ecdsa: reject negative inputs. The fact that crypto/ecdsa.Verify didn't reject negative inputs was a mistake on my part: I had unsigned numbers on the brain. However, it doesn't generally cause problems. (ModInverse results in zero, which results in x being zero, which is rejected.) The amd64 P-256 code will crash when given a large, negative input. This fixes both crypto/ecdsa to reject these values and also the P-256 code to ignore the sign of inputs. Change-Id: I6370ed7ca8125e53225866f55b616a4022b818f8 Reviewed-on: https://go-review.googlesource.com/22093 Run-TryBot: Adam Langley TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/crypto/ecdsa/ecdsa.go | 2 +- src/crypto/ecdsa/ecdsa_test.go | 23 +++++++++++++++++++++++ src/crypto/elliptic/p256_amd64.go | 8 ++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index e63bd8669ef443..288e366a882de2 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -228,7 +228,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { c := pub.Curve N := c.Params().N - if r.Sign() == 0 || s.Sign() == 0 { + if r.Sign() <= 0 || s.Sign() <= 0 { return false } if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go index 5e588b92582bbc..fc25fd74a78ce7 100644 --- a/src/crypto/ecdsa/ecdsa_test.go +++ b/src/crypto/ecdsa/ecdsa_test.go @@ -296,3 +296,26 @@ func TestVectors(t *testing.T) { } } } + +func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) { + key, err := GenerateKey(curve, rand.Reader) + if err != nil { + t.Errorf("failed to generate key for %q", tag) + } + + var hash [32]byte + r := new(big.Int).SetInt64(1) + r.Lsh(r, 550 /* larger than any supported curve */) + r.Neg(r) + + if Verify(&key.PublicKey, hash[:], r, r) { + t.Errorf("bogus signature accepted for %q", tag) + } +} + +func TestNegativeInputs(t *testing.T) { + testNegativeInputs(t, elliptic.P224(), "p224") + testNegativeInputs(t, elliptic.P256(), "p256") + testNegativeInputs(t, elliptic.P384(), "p384") + testNegativeInputs(t, elliptic.P521(), "p521") +} diff --git a/src/crypto/elliptic/p256_amd64.go b/src/crypto/elliptic/p256_amd64.go index e96933e0c55667..66b7cf8dc512a4 100644 --- a/src/crypto/elliptic/p256_amd64.go +++ b/src/crypto/elliptic/p256_amd64.go @@ -93,10 +93,14 @@ func p256PointAddAsm(res, in1, in2 []uint64) func p256PointDoubleAsm(res, in []uint64) func (curve p256Curve) Inverse(k *big.Int) *big.Int { + if k.Sign() < 0 { + // This should never happen. + k = new(big.Int).Neg(k) + } + if k.Cmp(p256.N) >= 0 { // This should never happen. - reducedK := new(big.Int).Mod(k, p256.N) - k = reducedK + k = new(big.Int).Mod(k, p256.N) } // table will store precomputed powers of x. The four words at index From 6cd698d71da92aeb4540c378213ac4a1c6687097 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Mon, 7 Mar 2016 22:31:31 -0600 Subject: [PATCH 141/267] crypto/x509: add Admin & User Keychains to FetchPEMRoots on Darwin in root_cgo_darwin.go only certificates from the System Domain were being used in FetchPEMRoots. This patch adds support for getting certificates from all three domains (System, Admin, User). Also it will only read trusted certificates from those Keychains. Because it is possible to trust a non Root certificate, this patch also adds a checks to see if the Subject and Issuer name are the same. Fixes #14514 Change-Id: Ia03936d7a61d1e24e99f31c92f9927ae48b2b494 Reviewed-on: https://go-review.googlesource.com/20351 Reviewed-by: Russ Cox --- src/crypto/x509/root_cgo_darwin.go | 76 ++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go index f067cd7cf432fc..0e2fb357ee9040 100644 --- a/src/crypto/x509/root_cgo_darwin.go +++ b/src/crypto/x509/root_cgo_darwin.go @@ -21,41 +21,69 @@ package x509 // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after // we've consumed its content. int FetchPEMRoots(CFDataRef *pemRoots) { - if (pemRoots == NULL) { - return -1; - } + // Get certificates from all domains, not just System, this lets + // the user add CAs to their "login" keychain, and Admins to add + // to the "System" keychain + SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem, + kSecTrustSettingsDomainAdmin, + kSecTrustSettingsDomainUser }; - CFArrayRef certs = NULL; - OSStatus err = SecTrustCopyAnchorCertificates(&certs); - if (err != noErr) { + int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain); + if (pemRoots == NULL) { return -1; } CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); - int i, ncerts = CFArrayGetCount(certs); - for (i = 0; i < ncerts; i++) { - CFDataRef data = NULL; - SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); - if (cert == NULL) { - continue; - } - - // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. - // Once we support weak imports via cgo we should prefer that, and fall back to this - // for older systems. - err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); + for (int i = 0; i < numDomains; i++) { + CFArrayRef certs = NULL; + // Only get certificates from domain that are trusted + OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs); if (err != noErr) { continue; } - if (data != NULL) { - CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); - CFRelease(data); - } - } + int numCerts = CFArrayGetCount(certs); + for (int j = 0; j < numCerts; j++) { + CFDataRef data = NULL; + CFErrorRef errRef = NULL; + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j); + if (cert == NULL) { + continue; + } + // We only want to add Root CAs, so make sure Subject and Issuer Name match + CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef); + if (errRef != NULL) { + CFRelease(errRef); + continue; + } + CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef); + if (errRef != NULL) { + CFRelease(subjectName); + CFRelease(errRef); + continue; + } + Boolean equal = CFEqual(subjectName, issuerName); + CFRelease(subjectName); + CFRelease(issuerName); + if (!equal) { + continue; + } - CFRelease(certs); + // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. + // Once we support weak imports via cgo we should prefer that, and fall back to this + // for older systems. + err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); + if (err != noErr) { + continue; + } + if (data != NULL) { + CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); + CFRelease(data); + } + } + CFRelease(certs); + } *pemRoots = combinedData; return 0; } From 9d73e146dade6553f2365de2ada0156dcb6026d9 Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Tue, 19 Apr 2016 19:05:53 +0300 Subject: [PATCH 142/267] hash/crc64: Use slicing by 8. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to crc32 slicing by 8. This also fixes a Crc64KB benchmark actually using 1024 bytes. Crc64/ISO64KB-4 147µs ± 0% 37µs ± 0% -75.05% (p=0.000 n=18+18) Crc64/ISO4KB-4 9.19µs ± 0% 2.33µs ± 0% -74.70% (p=0.000 n=19+20) Crc64/ISO1KB-4 2.31µs ± 0% 0.60µs ± 0% -73.81% (p=0.000 n=19+15) Crc64/ECMA64KB-4 147µs ± 0% 37µs ± 0% -75.05% (p=0.000 n=20+20) Crc64/Random64KB-4 147µs ± 0% 41µs ± 0% -72.17% (p=0.000 n=20+18) Crc64/Random16KB-4 36.7µs ± 0% 36.5µs ± 0% -0.54% (p=0.000 n=18+19) name old speed new speed delta Crc64/ISO64KB-4 446MB/s ± 0% 1788MB/s ± 0% +300.72% (p=0.000 n=18+18) Crc64/ISO4KB-4 446MB/s ± 0% 1761MB/s ± 0% +295.20% (p=0.000 n=18+20) Crc64/ISO1KB-4 444MB/s ± 0% 1694MB/s ± 0% +281.46% (p=0.000 n=19+20) Crc64/ECMA64KB-4 446MB/s ± 0% 1788MB/s ± 0% +300.77% (p=0.000 n=20+20) Crc64/Random64KB-4 446MB/s ± 0% 1603MB/s ± 0% +259.32% (p=0.000 n=20+18) Crc64/Random16KB-4 446MB/s ± 0% 448MB/s ± 0% +0.54% (p=0.000 n=18+20) Change-Id: I1c7621d836c486d6bfc41dbe1ec2ff9ab11aedfc Reviewed-on: https://go-review.googlesource.com/22222 Run-TryBot: Ilya Tocar TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/hash/crc64/crc64.go | 58 ++++++++++++++++++++++++++++++++++++ src/hash/crc64/crc64_test.go | 29 +++++++++++++++--- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/hash/crc64/crc64.go b/src/hash/crc64/crc64.go index 54cc56055e48fa..e939c2a06ac29e 100644 --- a/src/hash/crc64/crc64.go +++ b/src/hash/crc64/crc64.go @@ -24,9 +24,25 @@ const ( // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint64 +var ( + slicing8TableISO = makeSlicingBy8Table(makeTable(ISO)) + slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA)) +) + // MakeTable returns a Table constructed from the specified polynomial. // The contents of this Table must not be modified. func MakeTable(poly uint64) *Table { + switch poly { + case ISO: + return &slicing8TableISO[0] + case ECMA: + return &slicing8TableECMA[0] + default: + return makeTable(poly) + } +} + +func makeTable(poly uint64) *Table { t := new(Table) for i := 0; i < 256; i++ { crc := uint64(i) @@ -42,6 +58,19 @@ func MakeTable(poly uint64) *Table { return t } +func makeSlicingBy8Table(t *Table) *[8]Table { + var helperTable [8]Table + helperTable[0] = *t + for i := 0; i < 256; i++ { + crc := t[i] + for j := 1; j < 8; j++ { + crc = t[crc&0xff] ^ (crc >> 8) + helperTable[j][i] = crc + } + } + return &helperTable +} + // digest represents the partial evaluation of a checksum. type digest struct { crc uint64 @@ -61,6 +90,35 @@ func (d *digest) Reset() { d.crc = 0 } func update(crc uint64, tab *Table, p []byte) uint64 { crc = ^crc + // Table comparison is somewhat expensive, so avoid it for small sizes + for len(p) >= 64 { + var helperTable *[8]Table + if *tab == slicing8TableECMA[0] { + helperTable = slicing8TableECMA + } else if *tab == slicing8TableISO[0] { + helperTable = slicing8TableISO + // For smaller sizes creating extended table takes too much time + } else if len(p) > 16384 { + helperTable = makeSlicingBy8Table(tab) + } else { + break + } + // Update using slicing-by-8 + for len(p) > 8 { + crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | + uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 + crc = helperTable[7][crc&0xff] ^ + helperTable[6][(crc>>8)&0xff] ^ + helperTable[5][(crc>>16)&0xff] ^ + helperTable[4][(crc>>24)&0xff] ^ + helperTable[3][(crc>>32)&0xff] ^ + helperTable[2][(crc>>40)&0xff] ^ + helperTable[1][(crc>>48)&0xff] ^ + helperTable[0][crc>>56] + p = p[8:] + } + } + // For reminders or small sizes for _, v := range p { crc = tab[byte(crc)^v] ^ (crc >> 8) } diff --git a/src/hash/crc64/crc64_test.go b/src/hash/crc64/crc64_test.go index 80dca47f3d8b2c..480b150e132dcf 100644 --- a/src/hash/crc64/crc64_test.go +++ b/src/hash/crc64/crc64_test.go @@ -72,13 +72,13 @@ func TestGolden(t *testing.T) { } } -func BenchmarkISOCrc64KB(b *testing.B) { - b.SetBytes(1024) - data := make([]byte, 1024) +func bench(b *testing.B, poly uint64, size int64) { + b.SetBytes(size) + data := make([]byte, size) for i := range data { data[i] = byte(i) } - h := New(MakeTable(ISO)) + h := New(MakeTable(poly)) in := make([]byte, 0, h.Size()) b.ResetTimer() @@ -88,3 +88,24 @@ func BenchmarkISOCrc64KB(b *testing.B) { h.Sum(in) } } + +func BenchmarkCrc64(b *testing.B) { + b.Run("ISO64KB", func(b *testing.B) { + bench(b, ISO, 64<<10) + }) + b.Run("ISO4KB", func(b *testing.B) { + bench(b, ISO, 4<<10) + }) + b.Run("ISO1KB", func(b *testing.B) { + bench(b, ISO, 1<<10) + }) + b.Run("ECMA64KB", func(b *testing.B) { + bench(b, ECMA, 64<<10) + }) + b.Run("Random64KB", func(b *testing.B) { + bench(b, 0x777, 64<<10) + }) + b.Run("Random16KB", func(b *testing.B) { + bench(b, 0x777, 16<<10) + }) +} From 4d2ac544a437aaf7bbd78d1a46baa5108945f06e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 30 Apr 2016 19:57:28 -0700 Subject: [PATCH 143/267] net/http: fix spurious logging in Transport when server closes idle conn In https://golang.org/3210, Transport errors occurring before receiving response headers were wrapped in another error type to indicate to the retry logic elsewhere that the request might be re-tryable. But a check for err == io.EOF was missed, which then became false once io.EOF was wrapped in the beforeRespHeaderError type. The beforeRespHeaderError was too fragile. Remove it. I tried to fix it in an earlier version of this CL and just broke different things instead. Also remove the "markBroken" method. It's redundant and confusing. Also, rename the checkTransportResend method to shouldRetryRequest and make it return a bool instead of an error. This also helps readability. Now the code recognizes the two main reasons we'd want to retry a request: because we never wrote the request in the first place (so: count the number of bytes we've written), or because the server hung up on us before we received response headers for an idempotent request. As an added bonus, this could make POST requests safely re-tryable since we know we haven't written anything yet. But it's too late in Go 1.7 to enable that, so we'll do that later (filed #15723). This also adds a new internal (package http) test, since testing this blackbox at higher levels in transport_test wasn't possible. Fixes #15446 Change-Id: I2c1dc03b1f1ebdf3f04eba81792bd5c4fb6b6b66 Reviewed-on: https://go-review.googlesource.com/23160 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/transport.go | 213 +++++++++++++++--------- src/net/http/transport_internal_test.go | 69 ++++++++ 2 files changed, 205 insertions(+), 77 deletions(-) create mode 100644 src/net/http/transport_internal_test.go diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 7fdd94e05bc768..865dbdd50824e0 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -387,47 +387,47 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { if err == nil { return resp, nil } - if err := checkTransportResend(err, req, pconn); err != nil { + if !pconn.shouldRetryRequest(req, err) { return nil, err } testHookRoundTripRetried() } } -// checkTransportResend checks whether a failed HTTP request can be -// resent on a new connection. The non-nil input error is the error from -// roundTrip, which might be wrapped in a beforeRespHeaderError error. -// -// The return value is either nil to retry the request, the provided -// err unmodified, or the unwrapped error inside a -// beforeRespHeaderError. -func checkTransportResend(err error, req *Request, pconn *persistConn) error { - brhErr, ok := err.(beforeRespHeaderError) - if !ok { - return err +// shouldRetryRequest reports whether we should retry sending a failed +// HTTP request on a new connection. The non-nil input error is the +// error from roundTrip. +func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool { + if err == errMissingHost { + // User error. + return false } - err = brhErr.error // unwrap the custom error in case we return it - if err != errMissingHost && pconn.isReused() && req.isReplayable() { - // If we try to reuse a connection that the server is in the process of - // closing, we may end up successfully writing out our request (or a - // portion of our request) only to find a connection error when we try to - // read from (or finish writing to) the socket. - - // There can be a race between the socket pool checking whether a socket - // is still connected, receiving the FIN, and sending/reading data on a - // reused socket. If we receive the FIN between the connectedness check - // and writing/reading from the socket, we may first learn the socket is - // disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most - // likely happen when trying to retrieve its IP address. See - // http://crbug.com/105824 for more details. - - // We resend a request only if we reused a keep-alive connection and did - // not yet receive any header data. This automatically prevents an - // infinite resend loop because we'll run out of the cached keep-alive - // connections eventually. - return nil + if !pc.isReused() { + // This was a fresh connection. There's no reason the server + // should've hung up on us. + // + // Also, if we retried now, we could loop forever + // creating new connections and retrying if the server + // is just hanging up on us because it doesn't like + // our request (as opposed to sending an error). + return false } - return err + if !req.isReplayable() { + // Don't retry non-idempotent requests. + + // TODO: swap the nothingWrittenError and isReplayable checks, + // putting the "if nothingWrittenError => return true" case + // first, per golang.org/issue/15723 + return false + } + if _, ok := err.(nothingWrittenError); ok { + // We never wrote anything, so it's safe to retry. + return true + } + if err == errServerClosedIdle || err == errServerClosedConn { + return true + } + return false // conservatively } // ErrSkipAltProtocol is a sentinel error value defined by Transport.RegisterProtocol. @@ -570,7 +570,8 @@ var ( errTooManyIdleHost = errors.New("http: putIdleConn: too many idle connections for host") errCloseIdleConns = errors.New("http: CloseIdleConnections called") errReadLoopExiting = errors.New("http: persistConn.readLoop exiting") - errServerClosedIdle = errors.New("http: server closed idle conn") + errServerClosedIdle = errors.New("http: server closed idle connection") + errServerClosedConn = errors.New("http: server closed connection") errIdleConnTimeout = errors.New("http: idle connection timeout") ) @@ -881,12 +882,13 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) { pconn := &persistConn{ - t: t, - cacheKey: cm.key(), - reqch: make(chan requestAndChan, 1), - writech: make(chan writeRequest, 1), - closech: make(chan struct{}), - writeErrCh: make(chan error, 1), + t: t, + cacheKey: cm.key(), + reqch: make(chan requestAndChan, 1), + writech: make(chan writeRequest, 1), + closech: make(chan struct{}), + writeErrCh: make(chan error, 1), + writeLoopDone: make(chan struct{}), } tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil if tlsDial { @@ -1003,12 +1005,28 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon } pconn.br = bufio.NewReader(pconn) - pconn.bw = bufio.NewWriter(pconn.conn) + pconn.bw = bufio.NewWriter(persistConnWriter{pconn}) go pconn.readLoop() go pconn.writeLoop() return pconn, nil } +// persistConnWriter is the io.Writer written to by pc.bw. +// It accumulates the number of bytes written to the underlying conn, +// so the retry logic can determine whether any bytes made it across +// the wire. +// This is exactly 1 pointer field wide so it can go into an interface +// without allocation. +type persistConnWriter struct { + pc *persistConn +} + +func (w persistConnWriter) Write(p []byte) (n int, err error) { + n, err = w.pc.conn.Write(p) + w.pc.nwrite += int64(n) + return +} + // useProxy reports whether requests to addr should use a proxy, // according to the NO_PROXY or no_proxy environment variable. // addr is always a canonicalAddr with a host and port. @@ -1142,6 +1160,7 @@ type persistConn struct { tlsState *tls.ConnectionState br *bufio.Reader // from conn bw *bufio.Writer // to conn + nwrite int64 // bytes written reqch chan requestAndChan // written by roundTrip; read by readLoop writech chan writeRequest // written by roundTrip; read by writeLoop closech chan struct{} // closed when conn closed @@ -1154,6 +1173,8 @@ type persistConn struct { // whether or not a connection can be reused. Issue 7569. writeErrCh chan error + writeLoopDone chan struct{} // closed when write loop ends + // Both guarded by Transport.idleMu: idleAt time.Time // time it last become idle idleTimer *time.Timer // holding an AfterFunc to close it @@ -1195,7 +1216,7 @@ func (pc *persistConn) Read(p []byte) (n int, err error) { // isBroken reports whether this connection is in a known broken state. func (pc *persistConn) isBroken() bool { pc.mu.Lock() - b := pc.broken + b := pc.closed != nil pc.mu.Unlock() return b } @@ -1247,6 +1268,56 @@ func (pc *persistConn) closeConnIfStillIdle() { pc.close(errIdleConnTimeout) } +// mapRoundTripErrorFromReadLoop maps the provided readLoop error into +// the error value that should be returned from persistConn.roundTrip. +// +// The startBytesWritten value should be the value of pc.nwrite before the roundTrip +// started writing the request. +func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, err error) (out error) { + if err == nil { + return nil + } + if pc.isCanceled() { + return errRequestCanceled + } + if err == errServerClosedIdle || err == errServerClosedConn { + return err + } + if pc.isBroken() { + <-pc.writeLoopDone + if pc.nwrite == startBytesWritten { + return nothingWrittenError{err} + } + } + return err +} + +// mapRoundTripErrorAfterClosed returns the error value to be propagated +// up to Transport.RoundTrip method when persistConn.roundTrip sees +// its pc.closech channel close, indicating the persistConn is dead. +// (after closech is closed, pc.closed is valid). +func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) error { + if pc.isCanceled() { + return errRequestCanceled + } + err := pc.closed + if err == errServerClosedIdle || err == errServerClosedConn { + // Don't decorate + return err + } + + // Wait for the writeLoop goroutine to terminated, and then + // see if we actually managed to write anything. If not, we + // can retry the request. + <-pc.writeLoopDone + if pc.nwrite == startBytesWritten { + return nothingWrittenError{err} + } + + return fmt.Errorf("net/http: HTTP/1.x transport connection broken: %v", err) + +} + func (pc *persistConn) readLoop() { closeErr := errReadLoopExiting // default value, if not changed below defer func() { @@ -1283,9 +1354,6 @@ func (pc *persistConn) readLoop() { for alive { pc.readLimit = pc.maxHeaderResponseSize() _, err := pc.br.Peek(1) - if err != nil { - err = beforeRespHeaderError{err} - } pc.mu.Lock() if pc.numExpectedResponses == 0 { @@ -1301,12 +1369,16 @@ func (pc *persistConn) readLoop() { var resp *Response if err == nil { resp, err = pc.readResponse(rc, trace) + } else { + err = errServerClosedConn + closeErr = err } if err != nil { if pc.readLimit <= 0 { err = fmt.Errorf("net/http: server response headers exceeded %d bytes; aborted", pc.maxHeaderResponseSize()) } + // If we won't be able to retry this request later (from the // roundTrip goroutine), mark it as done now. // BEFORE the send on rc.ch, as the client might re-use the @@ -1314,7 +1386,7 @@ func (pc *persistConn) readLoop() { // t.setReqCanceler from this persistConn while the Transport // potentially spins up a different persistConn for the // caller's subsequent request. - if checkTransportResend(err, rc.req, pc) != nil { + if !pc.shouldRetryRequest(rc.req, err) { pc.t.setReqCanceler(rc.req, nil) } select { @@ -1501,24 +1573,33 @@ func (pc *persistConn) waitForContinue(continueCh <-chan struct{}) func() bool { } } +// nothingWrittenError wraps a write errors which ended up writing zero bytes. +type nothingWrittenError struct { + error +} + func (pc *persistConn) writeLoop() { + defer close(pc.writeLoopDone) for { select { case wr := <-pc.writech: - if pc.isBroken() { - wr.ch <- errors.New("http: can't write HTTP request on broken connection") - continue - } + startBytesWritten := pc.nwrite err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh)) if err == nil { err = pc.bw.Flush() } if err != nil { - pc.markBroken() wr.req.Request.closeBody() + if pc.nwrite == startBytesWritten { + err = nothingWrittenError{err} + } } pc.writeErrCh <- err // to the body reader, which might recycle us wr.ch <- err // to the roundTrip function + if err != nil { + pc.close(err) + return + } case <-pc.closech: return } @@ -1619,12 +1700,6 @@ var ( testHookReadLoopBeforeNextRead = nop ) -// beforeRespHeaderError is used to indicate when an IO error has occurred before -// any header data was received. -type beforeRespHeaderError struct { - error -} - func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { testHookEnterRoundTrip() if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) { @@ -1680,6 +1755,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err // Write the request concurrently with waiting for a response, // in case the server decides to reply before reading our full // request body. + startBytesWritten := pc.nwrite writeErrCh := make(chan error, 1) pc.writech <- writeRequest{req, writeErrCh, continueCh} @@ -1704,7 +1780,7 @@ WaitResponse: if pc.isCanceled() { err = errRequestCanceled } - re = responseAndError{err: beforeRespHeaderError{err}} + re = responseAndError{err: err} pc.close(fmt.Errorf("write error: %v", err)) break WaitResponse } @@ -1714,22 +1790,14 @@ WaitResponse: respHeaderTimer = timer.C } case <-pc.closech: - var err error - if pc.isCanceled() { - err = errRequestCanceled - } else { - err = beforeRespHeaderError{fmt.Errorf("net/http: HTTP/1 transport connection broken: %v", pc.closed)} - } - re = responseAndError{err: err} + re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(startBytesWritten)} break WaitResponse case <-respHeaderTimer: pc.close(errTimeout) re = responseAndError{err: errTimeout} break WaitResponse case re = <-resc: - if re.err != nil && pc.isCanceled() { - re.err = errRequestCanceled - } + re.err = pc.mapRoundTripErrorFromReadLoop(startBytesWritten, re.err) break WaitResponse case <-cancelChan: pc.t.CancelRequest(req.Request) @@ -1749,15 +1817,6 @@ WaitResponse: return re.res, re.err } -// markBroken marks a connection as broken (so it's not reused). -// It differs from close in that it doesn't close the underlying -// connection for use when it's still being read. -func (pc *persistConn) markBroken() { - pc.mu.Lock() - defer pc.mu.Unlock() - pc.broken = true -} - // markReused marks this connection as having been successfully used for a // request and response. func (pc *persistConn) markReused() { diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go new file mode 100644 index 00000000000000..a157d906300a2c --- /dev/null +++ b/src/net/http/transport_internal_test.go @@ -0,0 +1,69 @@ +// 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. + +// White-box tests for transport.go (in package http instead of http_test). + +package http + +import ( + "errors" + "net" + "testing" +) + +// Issue 15446: incorrect wrapping of errors when server closes an idle connection. +func TestTransportPersistConnReadLoopEOF(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + + connc := make(chan net.Conn, 1) + go func() { + defer close(connc) + c, err := ln.Accept() + if err != nil { + t.Error(err) + return + } + connc <- c + }() + + tr := new(Transport) + req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil) + treq := &transportRequest{Request: req} + cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()} + pc, err := tr.getConn(treq, cm) + if err != nil { + t.Fatal(err) + } + defer pc.close(errors.New("test over")) + + conn := <-connc + if conn == nil { + // Already called t.Error in the accept goroutine. + return + } + conn.Close() // simulate the server hanging up on the client + + _, err = pc.roundTrip(treq) + if err != errServerClosedConn && err != errServerClosedIdle { + t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err) + } + + <-pc.closech + err = pc.closed + if err != errServerClosedConn && err != errServerClosedIdle { + t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err) + } +} + +func newLocalListener(t *testing.T) net.Listener { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + ln, err = net.Listen("tcp6", "[::1]:0") + } + if err != nil { + t.Fatal(err) + } + return ln +} From 1119af89767dc4086cba336e732afcea084c8c34 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 04:42:37 +0000 Subject: [PATCH 144/267] net/http: update bundled x/net/http2 for httptrace changes Updates x/net/http2 to 3b99394 for golang.org/cl/23205 And associated tests. Fixes #12580 Change-Id: I1f4b59267b453d241f2afaa315b7fe10d477e52d Reviewed-on: https://go-review.googlesource.com/23206 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/clientserver_test.go | 7 ++++ src/net/http/h2_bundle.go | 58 +++++++++++++++++++++++++++++++ src/net/http/httptrace/trace.go | 1 + src/net/http/transport_test.go | 38 +++++++++++--------- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index 39c1eaa04afadb..b1b7d137d93c52 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -44,6 +44,13 @@ func (t *clientServerTest) close() { t.ts.Close() } +func (t *clientServerTest) scheme() string { + if t.h2 { + return "https" + } + return "http" +} + const ( h1Mode = false h2Mode = true diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index c2a2d37f6dfaa8..21b10355a9d5b0 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -30,6 +30,7 @@ import ( "io/ioutil" "log" "net" + "net/http/httptrace" "net/textproto" "net/url" "os" @@ -1973,10 +1974,52 @@ func http2summarizeFrame(f http2Frame) string { return buf.String() } +type http2clientTrace httptrace.ClientTrace + func http2reqContext(r *Request) context.Context { return r.Context() } func http2setResponseUncompressed(res *Response) { res.Uncompressed = true } +func http2traceGotConn(req *Request, cc *http2ClientConn) { + trace := httptrace.ContextClientTrace(req.Context()) + if trace == nil || trace.GotConn == nil { + return + } + ci := httptrace.GotConnInfo{Conn: cc.tconn} + cc.mu.Lock() + ci.Reused = cc.nextStreamID > 1 + ci.WasIdle = len(cc.streams) == 0 + if ci.WasIdle { + ci.IdleTime = time.Now().Sub(cc.lastActive) + } + cc.mu.Unlock() + + trace.GotConn(ci) +} + +func http2traceWroteHeaders(trace *http2clientTrace) { + if trace != nil && trace.WroteHeaders != nil { + trace.WroteHeaders() + } +} + +func http2traceWroteRequest(trace *http2clientTrace, err error) { + if trace != nil && trace.WroteRequest != nil { + trace.WroteRequest(httptrace.WroteRequestInfo{Err: err}) + } +} + +func http2traceFirstResponseByte(trace *http2clientTrace) { + if trace != nil && trace.GotFirstResponseByte != nil { + trace.GotFirstResponseByte() + } +} + +func http2requestTrace(req *Request) *http2clientTrace { + trace := httptrace.ContextClientTrace(req.Context()) + return (*http2clientTrace)(trace) +} + var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1" type http2goroutineLock uint64 @@ -4879,6 +4922,8 @@ type http2ClientConn struct { bw *bufio.Writer br *bufio.Reader fr *http2Framer + lastActive time.Time + // Settings from peer: maxFrameSize uint32 maxConcurrentStreams uint32 @@ -4896,6 +4941,7 @@ type http2ClientConn struct { type http2clientStream struct { cc *http2ClientConn req *Request + trace *http2clientTrace // or nil ID uint32 resc chan http2resAndError bufPipe http2pipe // buffered pipe with the flow-controlled response payload @@ -5014,6 +5060,7 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err) return nil, err } + http2traceGotConn(req, cc) res, err := cc.RoundTrip(req) if http2shouldRetryRequest(req, err) { continue @@ -5335,6 +5382,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } cc.mu.Lock() + cc.lastActive = time.Now() if cc.closed || !cc.canTakeNewRequestLocked() { cc.mu.Unlock() return nil, http2errClientConnUnusable @@ -5342,6 +5390,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cs := cc.newStream() cs.req = req + cs.trace = http2requestTrace(req) hasBody := body != nil if !cc.t.disableCompression() && @@ -5357,6 +5406,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { endStream := !hasBody && !hasTrailers werr := cc.writeHeaders(cs.ID, endStream, hdrs) cc.wmu.Unlock() + http2traceWroteHeaders(cs.trace) cc.mu.Unlock() if werr != nil { @@ -5365,6 +5415,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } cc.forgetStreamID(cs.ID) + http2traceWroteRequest(cs.trace, werr) return nil, werr } @@ -5376,6 +5427,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { bodyCopyErrc <- cs.writeRequestBody(body, req.Body) }() } else { + http2traceWroteRequest(cs.trace, nil) if d := cc.responseHeaderTimeout(); d != 0 { timer := time.NewTimer(d) defer timer.Stop() @@ -5430,6 +5482,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { return nil, cs.resetErr case err := <-bodyCopyErrc: + http2traceWroteRequest(cs.trace, err) if err != nil { return nil, err } @@ -5729,6 +5782,7 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr defer cc.mu.Unlock() cs := cc.streams[id] if andRemove && cs != nil && !cc.closed { + cc.lastActive = time.Now() delete(cc.streams, id) close(cs.done) } @@ -5852,6 +5906,10 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro } else { return rl.processTrailers(cs, f) } + if cs.trace != nil { + + http2traceFirstResponseByte(cs.trace) + } res, err := rl.handleResponse(cs, f) if err != nil { diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go index 5d2c548b3cc310..6f187a7b694a84 100644 --- a/src/net/http/httptrace/trace.go +++ b/src/net/http/httptrace/trace.go @@ -90,6 +90,7 @@ type ClientTrace struct { // connection reuse is disabled via Transport.DisableKeepAlives. // PutIdleConn is called before the caller's Response.Body.Close // call returns. + // For HTTP/2, this hook is not currently used. PutIdleConn func(err error) // GotFirstResponseByte is called when the first byte of the response diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 328fd5727b9e6b..48b1b309d330b2 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3193,26 +3193,26 @@ func TestTransportResponseHeaderLength(t *testing.T) { } } -func TestTransportEventTrace(t *testing.T) { testTransportEventTrace(t, false) } +func TestTransportEventTrace(t *testing.T) { testTransportEventTrace(t, h1Mode, false) } +func TestTransportEventTrace_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, false) } // test a non-nil httptrace.ClientTrace but with all hooks set to zero. -func TestTransportEventTrace_NoHooks(t *testing.T) { testTransportEventTrace(t, true) } +func TestTransportEventTrace_NoHooks(t *testing.T) { testTransportEventTrace(t, h1Mode, true) } +func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, true) } -func testTransportEventTrace(t *testing.T, noHooks bool) { +func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { defer afterTest(t) const resBody = "some body" - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { if _, err := ioutil.ReadAll(r.Body); err != nil { t.Error(err) } io.WriteString(w, resBody) })) - defer ts.Close() - tr := &Transport{ - ExpectContinueTimeout: 1 * time.Second, + defer cst.close() + if !h2 { + cst.tr.ExpectContinueTimeout = 1 * time.Second } - defer tr.CloseIdleConnections() - c := &Client{Transport: tr} var mu sync.Mutex var buf bytes.Buffer @@ -3223,7 +3223,8 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { buf.WriteByte('\n') } - ip, port, err := net.SplitHostPort(ts.Listener.Addr().String()) + addrStr := cst.ts.Listener.Addr().String() + ip, port, err := net.SplitHostPort(addrStr) if err != nil { t.Fatal(err) } @@ -3237,7 +3238,7 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil }) - req, _ := NewRequest("POST", "http://dns-is-faked.golang:"+port, strings.NewReader("some body")) + req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader("some body")) trace := &httptrace.ClientTrace{ GetConn: func(hostPort string) { logf("Getting conn for %v ...", hostPort) }, GotConn: func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) }, @@ -3263,7 +3264,7 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) req.Header.Set("Expect", "100-continue") - res, err := c.Do(req) + res, err := cst.c.Do(req) if err != nil { t.Fatal(err) } @@ -3292,14 +3293,17 @@ func testTransportEventTrace(t *testing.T, noHooks bool) { wantSub("Getting conn for dns-is-faked.golang:" + port) wantSub("DNS start: {Host:dns-is-faked.golang}") wantSub("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err: Coalesced:false}") - wantSub("Connecting to tcp " + ts.Listener.Addr().String()) - wantSub("connected to tcp " + ts.Listener.Addr().String() + " = ") + wantSub("Connecting to tcp " + addrStr) + wantSub("connected to tcp " + addrStr + " = ") wantSub("Reused:false WasIdle:false IdleTime:0s") wantSub("first response byte") - wantSub("PutIdleConn = ") + if !h2 { + wantSub("PutIdleConn = ") + // TODO: implement these next two for Issue 13851 + wantSub("Wait100Continue") + wantSub("Got100Continue") + } wantSub("WroteRequest: {Err:}") - wantSub("Wait100Continue") - wantSub("Got100Continue") if strings.Contains(got, " to udp ") { t.Errorf("should not see UDP (DNS) connections") } From 5d92aefc18317578226a3873fb8fc37411cd2184 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 16:18:32 +0000 Subject: [PATCH 145/267] vendor, net/http: update vendored hpack Updates x/net/http2/hpack to rev 6050c111 for: http2/hpack: forbid excess and invalid padding in hpack decoder https://golang.org/cl/23067 Updates #15614 Change-Id: I3fbf9b265bfa5e49e6aa97d8c34e08214cfcc49a Reviewed-on: https://go-review.googlesource.com/23208 Reviewed-by: Carl Mastrangelo Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- .../x/net/http2/hpack/hpack_test.go | 41 ++++++++++++++++++ .../golang.org/x/net/http2/hpack/huffman.go | 42 ++++++++++++++----- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go b/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go index 6dc69f957990bb..4c7b17bfb14c0b 100644 --- a/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go +++ b/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go @@ -524,6 +524,47 @@ func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) { } } +func TestHuffmanDecodeExcessPadding(t *testing.T) { + tests := [][]byte{ + {0xff}, // Padding Exceeds 7 bits + {0x1f, 0xff}, // {"a", 1 byte excess padding} + {0x1f, 0xff, 0xff}, // {"a", 2 byte excess padding} + {0x1f, 0xff, 0xff, 0xff}, // {"a", 3 byte excess padding} + {0xff, 0x9f, 0xff, 0xff, 0xff}, // {"a", 29 bit excess padding} + {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol. + } + for i, in := range tests { + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err) + } + } +} + +func TestHuffmanDecodeEOS(t *testing.T) { + in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"} + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("error = %v; want ErrInvalidHuffman", err) + } +} + +func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) { + in := []byte{0x00, 0x01} // {"0", "0", "0"} + var buf bytes.Buffer + if err := huffmanDecode(&buf, 2, in); err != ErrStringLength { + t.Errorf("error = %v; want ErrStringLength", err) + } +} + +func TestHuffmanDecodeCorruptPadding(t *testing.T) { + in := []byte{0x00} + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("error = %v; want ErrInvalidHuffman", err) + } +} + func TestHuffmanDecode(t *testing.T) { tests := []struct { inHex, want string diff --git a/src/vendor/golang.org/x/net/http2/hpack/huffman.go b/src/vendor/golang.org/x/net/http2/hpack/huffman.go index eb4b1f05cd046d..8850e3946770ea 100644 --- a/src/vendor/golang.org/x/net/http2/hpack/huffman.go +++ b/src/vendor/golang.org/x/net/http2/hpack/huffman.go @@ -48,12 +48,16 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") // maxLen bytes will return ErrStringLength. func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { n := rootHuffmanNode - cur, nbits := uint(0), uint8(0) + // cur is the bit buffer that has not been fed into n. + // cbits is the number of low order bits in cur that are valid. + // sbits is the number of bits of the symbol prefix being decoded. + cur, cbits, sbits := uint(0), uint8(0), uint8(0) for _, b := range v { cur = cur<<8 | uint(b) - nbits += 8 - for nbits >= 8 { - idx := byte(cur >> (nbits - 8)) + cbits += 8 + sbits += 8 + for cbits >= 8 { + idx := byte(cur >> (cbits - 8)) n = n.children[idx] if n == nil { return ErrInvalidHuffman @@ -63,22 +67,40 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { return ErrStringLength } buf.WriteByte(n.sym) - nbits -= n.codeLen + cbits -= n.codeLen n = rootHuffmanNode + sbits = cbits } else { - nbits -= 8 + cbits -= 8 } } } - for nbits > 0 { - n = n.children[byte(cur<<(8-nbits))] - if n.children != nil || n.codeLen > nbits { + for cbits > 0 { + n = n.children[byte(cur<<(8-cbits))] + if n == nil { + return ErrInvalidHuffman + } + if n.children != nil || n.codeLen > cbits { break } + if maxLen != 0 && buf.Len() == maxLen { + return ErrStringLength + } buf.WriteByte(n.sym) - nbits -= n.codeLen + cbits -= n.codeLen n = rootHuffmanNode + sbits = cbits + } + if sbits > 7 { + // Either there was an incomplete symbol, or overlong padding. + // Both are decoding errors per RFC 7541 section 5.2. + return ErrInvalidHuffman } + if mask := uint(1< Date: Wed, 18 May 2016 15:42:54 +0000 Subject: [PATCH 146/267] net/http: allow Client.CheckRedirect to use most recent response Fixes #10069 Change-Id: I3819ff597d5a0c8e785403bf9d65a054f50655a6 Reviewed-on: https://go-review.googlesource.com/23207 Reviewed-by: Russ Cox --- src/net/http/client.go | 50 ++++++++++++++++++++++++++----------- src/net/http/client_test.go | 38 ++++++++++++++++++++++++++++ src/net/http/request.go | 5 ++++ src/net/http/response.go | 2 +- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index 1127634beca3b9..993c247eef536a 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -47,6 +47,9 @@ type Client struct { // method returns both the previous Response (with its Body // closed) and CheckRedirect's error (wrapped in a url.Error) // instead of issuing the Request req. + // As a special case, if CheckRedirect returns ErrUseLastResponse, + // then the most recent response is returned with its body + // unclosed, along with a nil error. // // If CheckRedirect is nil, the Client uses its default policy, // which is to stop after 10 consecutive requests. @@ -417,6 +420,12 @@ func (c *Client) Get(url string) (resp *Response, err error) { func alwaysFalse() bool { return false } +// ErrUseLastResponse can be returned by Client.CheckRedirect hooks to +// control how redirects are processed. If returned, the next request +// is not sent and the most recent response is returned with its body +// unclosed. +var ErrUseLastResponse = errors.New("net/http: use last response") + // checkRedirect calls either the user's configured CheckRedirect // function, or the default. func (c *Client) checkRedirect(req *Request, via []*Request) error { @@ -467,11 +476,12 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo } ireq := reqs[0] req = &Request{ - Method: ireq.Method, - URL: u, - Header: make(Header), - Cancel: ireq.Cancel, - ctx: ireq.ctx, + Method: ireq.Method, + Response: resp, + URL: u, + Header: make(Header), + Cancel: ireq.Cancel, + ctx: ireq.ctx, } if ireq.Method == "POST" || ireq.Method == "PUT" { req.Method = "GET" @@ -481,7 +491,27 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" { req.Header.Set("Referer", ref) } - if err := c.checkRedirect(req, reqs); err != nil { + err = c.checkRedirect(req, reqs) + + // Sentinel error to let users select the + // previous response, without closing its + // body. See Issue 10069. + if err == ErrUseLastResponse { + return resp, nil + } + + // Close the previous response's body. But + // read at least some of the body so if it's + // small the underlying TCP connection will be + // re-used. No need to check for errors: if it + // fails, the Transport won't reuse it anyway. + const maxBodySlurpSize = 2 << 10 + if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { + io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) + } + resp.Body.Close() + + if err != nil { // Special case for Go 1 compatibility: return both the response // and an error if the CheckRedirect function failed. // See https://golang.org/issue/3795 @@ -508,14 +538,6 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo if !shouldRedirect(resp.StatusCode) { return resp, nil } - - // Read the body if small so underlying TCP connection will be re-used. - // No need to check for errors: if it fails, Transport won't reuse it anyway. - const maxBodySlurpSize = 2 << 10 - if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { - io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) - } - resp.Body.Close() } } diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 6f7ab965cbcf94..a9b1948005cb66 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -366,6 +366,44 @@ func TestPostRedirects(t *testing.T) { } } +func TestClientRedirectUseResponse(t *testing.T) { + defer afterTest(t) + const body = "Hello, world." + var ts *httptest.Server + ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + if strings.Contains(r.URL.Path, "/other") { + io.WriteString(w, "wrong body") + } else { + w.Header().Set("Location", ts.URL+"/other") + w.WriteHeader(StatusFound) + io.WriteString(w, body) + } + })) + defer ts.Close() + + c := &Client{CheckRedirect: func(req *Request, via []*Request) error { + if req.Response == nil { + t.Error("expected non-nil Request.Response") + } + return ErrUseLastResponse + }} + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != StatusFound { + t.Errorf("status = %d; want %d", res.StatusCode, StatusFound) + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if string(slurp) != body { + t.Errorf("body = %q; want %q", slurp, body) + } +} + var expectedCookies = []*Cookie{ {Name: "ChocolateChip", Value: "tasty"}, {Name: "First", Value: "Hit"}, diff --git a/src/net/http/request.go b/src/net/http/request.go index 45507d23d14beb..e8780dea943c97 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -255,6 +255,11 @@ type Request struct { // set, it is undefined whether Cancel is respected. Cancel <-chan struct{} + // Response is the redirect response which caused this request + // to be created. This field is only populated during client + // redirects. + Response *Response + // ctx is either the client or server context. It should only // be modified via copying the whole Request using WithContext. // It is unexported to prevent people from using Context wrong diff --git a/src/net/http/response.go b/src/net/http/response.go index 0164a09c6a0d2a..979651c08a28b6 100644 --- a/src/net/http/response.go +++ b/src/net/http/response.go @@ -96,7 +96,7 @@ type Response struct { // any trailer values sent by the server. Trailer Header - // The Request that was sent to obtain this Response. + // Request is the request that was sent to obtain this Response. // Request's Body is nil (having already been consumed). // This is only populated for Client requests. Request *Request From d52022676da939cb183083da4ee0b614f86ac3b0 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 5 May 2016 13:25:19 -0700 Subject: [PATCH 147/267] html/template: mention risks of the CSS, HTML, JS, etc. types Fixes #15399 Change-Id: I5b9645cb9ddede6981ce0a005e0c6fdd8a751c6f Reviewed-on: https://go-review.googlesource.com/22824 Reviewed-by: Brad Fitzpatrick Reviewed-by: Minux Ma Reviewed-by: Russ Cox --- src/html/template/content.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/html/template/content.go b/src/html/template/content.go index 3715ed5c93805f..2e14bd1231f799 100644 --- a/src/html/template/content.go +++ b/src/html/template/content.go @@ -18,16 +18,28 @@ type ( // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. // See http://www.w3.org/TR/css3-syntax/#parsing and // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. CSS string // HTML encapsulates a known safe HTML document fragment. // It should not be used for HTML from a third-party, or HTML with // unclosed tags or comments. The outputs of a sound HTML sanitizer // and a template escaped by this package are fine for use with HTML. + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. HTML string // HTMLAttr encapsulates an HTML attribute from a trusted source, // for example, ` dir="ltr"`. + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. HTMLAttr string // JS encapsulates a known safe EcmaScript5 Expression, for example, @@ -37,6 +49,15 @@ type ( // statement/expression ambiguity as when passing an expression like // "{ foo: bar() }\n['foo']()", which is both a valid Expression and a // valid Program with a very different meaning. + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. + // + // Using JS to include valid but untrusted JSON is not safe. + // A safe alternative is to parse the JSON with json.Unmarshal and then + // pass the resultant object into the template, where it will be + // converted to sanitized JSON when presented in a JavaScript context. JS string // JSStr encapsulates a sequence of characters meant to be embedded @@ -46,6 +67,10 @@ type ( // | EscapeSequence // Note that LineContinuations are not allowed. // JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not. + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. JSStr string // URL encapsulates a known safe URL or URL substring (see RFC 3986). @@ -53,6 +78,10 @@ type ( // from a trusted source should go in the page, but by default dynamic // `javascript:` URLs are filtered out since they are a frequently // exploited injection vector. + // + // Use of this type presents a security risk: + // the encapsulated content should come from a trusted source, + // as it will be included verbatim in the template output. URL string ) From 3572c6418b5032fbd7e888e14fd9ad5afac85dfc Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 21 Apr 2016 19:28:28 -0700 Subject: [PATCH 148/267] cmd/compile: keep pointer input arguments live throughout function Introduce a KeepAlive op which makes sure that its argument is kept live until the KeepAlive. Use KeepAlive to mark pointer input arguments as live after each function call and at each return. We do this change only for pointer arguments. Those are the critical ones to handle because they might have finalizers. Doing compound arguments (slices, structs, ...) is more complicated because we would need to track field liveness individually (we do that for auto variables now, but inputs requires extra trickery). Turn off the automatic marking of args as live. That way, when args are explicitly nulled, plive will know that the original argument is dead. The KeepAlive op will be the eventual implementation of runtime.KeepAlive. Fixes #15277 Change-Id: I5f223e65d99c9f8342c03fbb1512c4d363e903e5 Reviewed-on: https://go-review.googlesource.com/22365 Reviewed-by: David Chase Reviewed-by: Russ Cox --- src/cmd/compile/internal/amd64/ssa.go | 12 ++++++ src/cmd/compile/internal/gc/plive.go | 21 ++--------- src/cmd/compile/internal/gc/ssa.go | 30 ++++++++++++++- src/cmd/compile/internal/gc/syntax.go | 36 +++++++++++++++--- src/cmd/compile/internal/gc/typecheck.go | 8 ++-- .../compile/internal/ssa/gen/genericOps.go | 9 +++-- src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/opGen.go | 7 ++++ src/cmd/compile/internal/ssa/regalloc.go | 17 +++++++++ test/fixedbugs/issue15277.go | 37 +++++++++++++++++++ 10 files changed, 145 insertions(+), 34 deletions(-) create mode 100644 test/fixedbugs/issue15277.go diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 54d878d92bd0af..756bcec75c88ee 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -878,6 +878,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.Gvarkill(v.Aux.(*gc.Node)) case ssa.OpVarLive: gc.Gvarlive(v.Aux.(*gc.Node)) + case ssa.OpKeepAlive: + if !v.Args[0].Type.IsPtrShaped() { + v.Fatalf("keeping non-pointer alive %v", v.Args[0]) + } + n, off := gc.AutoVar(v.Args[0]) + if n == nil { + v.Fatalf("KeepLive with non-spilled value %s %s", v, v.Args[0]) + } + if off != 0 { + v.Fatalf("KeepLive with non-zero offset spill location %s:%d", n, off) + } + gc.Gvarlive(n) case ssa.OpAMD64LoweredNilCheck: // Optimization - if the subsequent block has a load or store // at the same address, we don't need to issue this instruction. diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 87f4a11c0077c3..cf5359ecdf82ac 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -569,7 +569,9 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini for i, node := range vars { switch node.Class &^ PHEAP { case PPARAM: - bvset(uevar, int32(i)) + if !node.NotLiveAtEnd() { + bvset(uevar, int32(i)) + } // If the result had its address taken, it is being tracked // by the avarinit code, which does not use uevar. @@ -980,23 +982,6 @@ func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, l onebitwalktype1(node.Type, &xoffset, args) } } - - // The node list only contains declared names. - // If the receiver or arguments are unnamed, they will be omitted - // from the list above. Preserve those values - even though they are unused - - // in order to keep their addresses live for use in stack traces. - thisargtype := lv.fn.Type.Recvs() - - if thisargtype != nil { - xoffset = 0 - onebitwalktype1(thisargtype, &xoffset, args) - } - - inargtype := lv.fn.Type.Params() - if inargtype != nil { - xoffset = 0 - onebitwalktype1(inargtype, &xoffset, args) - } } // Construct a disembodied instruction. diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index fdf040d5af93bd..7bae8b46728ca4 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -161,6 +161,10 @@ func buildssa(fn *Node) *ssa.Func { // the function. s.returns = append(s.returns, n) } + if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() { + s.ptrargs = append(s.ptrargs, n) + n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly + } case PAUTO | PHEAP: // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n}) @@ -293,6 +297,10 @@ type state struct { // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars. returns []*Node + // list of PPARAM SSA-able pointer-shaped args. We ensure these are live + // throughout the function to help users avoid premature finalizers. + ptrargs []*Node + cgoUnsafeArgs bool noWB bool WBLineno int32 // line number of first write barrier. 0=no write barriers @@ -988,8 +996,7 @@ func (s *state) exit() *ssa.Block { // Store SSAable PPARAMOUT variables back to stack locations. for _, n := range s.returns { - aux := &ssa.ArgSymbol{Typ: n.Type, Node: n} - addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) + addr := s.decladdrs[n] val := s.variable(n, n.Type) s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem()) s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem()) @@ -998,6 +1005,16 @@ func (s *state) exit() *ssa.Block { // currently. } + // Keep input pointer args live until the return. This is a bandaid + // fix for 1.7 for what will become in 1.8 explicit runtime.KeepAlive calls. + // For <= 1.7 we guarantee that pointer input arguments live to the end of + // the function to prevent premature (from the user's point of view) + // execution of finalizers. See issue 15277. + // TODO: remove for 1.8? + for _, n := range s.ptrargs { + s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem()) + } + // Do actual return. m := s.mem() b := s.endBlock() @@ -2648,6 +2665,10 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { // Start exit block, find address of result. s.startBlock(bNext) + // Keep input pointer args live across calls. This is a bandaid until 1.8. + for _, n := range s.ptrargs { + s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem()) + } res := n.Left.Type.Results() if res.NumFields() == 0 || k != callNormal { // call has no return value. Continue with the next statement. @@ -2997,6 +3018,11 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val b.AddEdgeTo(bNext) s.startBlock(bNext) + // Keep input pointer args live across calls. This is a bandaid until 1.8. + for _, n := range s.ptrargs { + s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem()) + } + // Load results res := make([]*ssa.Value, len(results)) for i, t := range results { diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 8a675ac1579881..0135061e684bbd 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -68,11 +68,37 @@ type Node struct { Used bool Isddd bool // is the argument variadic Implicit bool - Addrtaken bool // address taken, even if not moved to heap - Assigned bool // is the variable ever assigned to - Likely int8 // likeliness of if statement - Hasbreak bool // has break statement - hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set + Addrtaken bool // address taken, even if not moved to heap + Assigned bool // is the variable ever assigned to + Likely int8 // likeliness of if statement + hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set + flags uint8 // TODO: store more bool fields in this flag field +} + +const ( + hasBreak = 1 << iota + notLiveAtEnd +) + +func (n *Node) HasBreak() bool { + return n.flags&hasBreak != 0 +} +func (n *Node) SetHasBreak(b bool) { + if b { + n.flags |= hasBreak + } else { + n.flags &^= hasBreak + } +} +func (n *Node) NotLiveAtEnd() bool { + return n.flags¬LiveAtEnd != 0 +} +func (n *Node) SetNotLiveAtEnd(b bool) { + if b { + n.flags |= notLiveAtEnd + } else { + n.flags &^= notLiveAtEnd + } } // Val returns the Val for the node. diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 7fccbe1a52b945..5c23d08cf36ccc 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -3786,12 +3786,12 @@ func markbreak(n *Node, implicit *Node) { case OBREAK: if n.Left == nil { if implicit != nil { - implicit.Hasbreak = true + implicit.SetHasBreak(true) } } else { lab := n.Left.Sym.Label if lab != nil { - lab.Def.Hasbreak = true + lab.Def.SetHasBreak(true) } } @@ -3867,7 +3867,7 @@ func (n *Node) isterminating() bool { if n.Left != nil { return false } - if n.Hasbreak { + if n.HasBreak() { return false } return true @@ -3876,7 +3876,7 @@ func (n *Node) isterminating() bool { return n.Nbody.isterminating() && n.Rlist.isterminating() case OSWITCH, OTYPESW, OSELECT: - if n.Hasbreak { + if n.HasBreak() { return false } def := 0 diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 8ea04c4fe532ef..8388ea89468730 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -382,9 +382,9 @@ var genericOps = []opData{ {name: "ComplexImag", argLength: 1}, // imag(arg0) // Strings - {name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len - {name: "StringPtr", argLength: 1}, // ptr(arg0) - {name: "StringLen", argLength: 1}, // len(arg0) + {name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len + {name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0) + {name: "StringLen", argLength: 1, typ: "Int"}, // len(arg0) // Interfaces {name: "IMake", argLength: 2}, // arg0=itab, arg1=data @@ -407,7 +407,7 @@ var genericOps = []opData{ {name: "LoadReg", argLength: 1}, // Used during ssa construction. Like Copy, but the arg has not been specified yet. - {name: "FwdRef"}, + {name: "FwdRef", aux: "Sym"}, // Unknown value. Used for Values whose values don't matter because they are dead code. {name: "Unknown"}, @@ -415,6 +415,7 @@ var genericOps = []opData{ {name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem {name: "VarKill", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem {name: "VarLive", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem + {name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem } // kind control successors implicit exit diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index af0ee4cccf0729..e271ed4ef6b9ab 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,7 +21,7 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive: + case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive: continue // ok not to lower } s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 2795d973336543..383f1ae5f3d165 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -617,6 +617,7 @@ const ( OpVarDef OpVarKill OpVarLive + OpKeepAlive ) var opcodeTable = [...]opInfo{ @@ -5357,6 +5358,7 @@ var opcodeTable = [...]opInfo{ }, { name: "FwdRef", + auxType: auxSym, argLen: 0, generic: true, }, @@ -5383,6 +5385,11 @@ var opcodeTable = [...]opInfo{ argLen: 1, generic: true, }, + { + name: "KeepAlive", + argLen: 2, + generic: true, + }, } func (o Op) Asm() obj.As { return opcodeTable[o].asm } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c9ef0d30174a04..c05e9ade779141 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -941,11 +941,28 @@ func (s *regAllocState) regalloc(f *Func) { s.advanceUses(v) continue } + if v.Op == OpKeepAlive { + // Make sure the argument to v is still live here. + s.advanceUses(v) + vi := &s.values[v.Args[0].ID] + if vi.spillUsed { + // Use the spill location. + v.SetArg(0, vi.spill) + b.Values = append(b.Values, v) + } else { + // No need to keep unspilled values live. + // These are typically rematerializeable constants like nil, + // or values of a variable that were modified since the last call. + v.Args[0].Uses-- + } + continue + } regspec := opcodeTable[v.Op].reg if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 { // No register allocation required (or none specified yet) s.freeRegs(regspec.clobbers) b.Values = append(b.Values, v) + s.advanceUses(v) continue } diff --git a/test/fixedbugs/issue15277.go b/test/fixedbugs/issue15277.go new file mode 100644 index 00000000000000..a3acc614bfc1ae --- /dev/null +++ b/test/fixedbugs/issue15277.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "runtime" + +type big [10 << 20]byte + +func f(x *big, start int64) { + if delta := inuse() - start; delta < 9<<20 { + println("after alloc: expected delta at least 9MB, got: ", delta) + } + x = nil + if delta := inuse() - start; delta > 1<<20 { + println("after drop: expected delta below 1MB, got: ", delta) + } + x = new(big) + if delta := inuse() - start; delta < 9<<20 { + println("second alloc: expected delta at least 9MB, got: ", delta) + } +} + +func main() { + x := inuse() + f(new(big), x) +} + +func inuse() int64 { + runtime.GC() + var st runtime.MemStats + runtime.ReadMemStats(&st) + return int64(st.Alloc) +} From 6ab45c09f6fc1bde56e3a72e50505b9a5021aaaf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 May 2016 09:02:40 -0700 Subject: [PATCH 149/267] runtime: add KeepAlive function Fixes #13347. Change-Id: I591a80a1566ce70efb5f68e3ad69e7e3ab98cd9b Reviewed-on: https://go-review.googlesource.com/23102 Reviewed-by: Austin Clements Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/mfinal.go | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index 6dce6d75011ec9..1a744e4a51e697 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -259,6 +259,24 @@ func runfinq() { // in initializers for package-level variables. Such objects may be // linker-allocated, not heap-allocated. // +// A finalizer may run as soon as an object becomes unreachable. +// In order to use finalizers correctly, the program must ensure that +// the object is reachable until it is no longer required. +// Objects stored in global variables, or that can be found by tracing +// pointers from a global variable, are reachable. For other objects, +// pass the object to a call of the KeepAlive function to mark the +// last point in the function where the object must be reachable. +// +// For example, if p points to a struct that contains a file descriptor d, +// and p has a finalizer that closes that file descriptor, and if the last +// use of p in a function is a call to syscall.Write(p.d, buf, size), then +// p may be unreachable as soon as the program enters syscall.Write. The +// finalizer may run at that moment, closing p.d, causing syscall.Write +// to fail because it is writing to a closed file descriptor (or, worse, +// to an entirely different file descriptor opened by a different goroutine). +// To avoid this problem, call runtime.KeepAlive(p) after the call to +// syscall.Write. +// // A single goroutine runs all finalizers for a program, sequentially. // If a finalizer must run for a long time, it should do so by starting // a new goroutine. @@ -416,3 +434,31 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) { } return } + +// Mark KeepAlive as noinline so that the current compiler will ensure +// that the argument is alive at the point of the function call. +// If it were inlined, it would disappear, and there would be nothing +// keeping the argument alive. Perhaps a future compiler will recognize +// runtime.KeepAlive specially and do something more efficient. +//go:noinline + +// KeepAlive marks its argument as currently reachable. +// This ensures that the object is not freed, and its finalizer is not run, +// before the point in the program where KeepAlive is called. +// +// A very simplified example showing where KeepAlive is required: +// type File struct { d int } +// d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0) +// // ... do something if err != nil ... +// p := &FILE{d} +// runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) }) +// var buf [10]byte +// n, err := syscall.Read(p.d, buf[:]) +// // Ensure p is not finalized until Read returns. +// runtime.KeepAlive(p) +// // No more uses of p after this point. +// +// Without the KeepAlive call, the finalizer could run at the start of +// syscall.Read, closing the file descriptor before syscall.Read makes +// the actual system call. +func KeepAlive(interface{}) {} From 075880a8e8f6363a554c100ad09a85d108953eea Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 18 May 2016 13:28:48 -0700 Subject: [PATCH 150/267] cmd/compile: fix build Run live vars test only on ssa builds. We can't just drop KeepAlive ops during regalloc. We need to replace them with copies. Change-Id: Ib4b3b1381415db88fdc2165fc0a9541b73ad9759 Reviewed-on: https://go-review.googlesource.com/23225 Run-TryBot: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/regalloc.go | 5 +++-- test/fixedbugs/issue15277.go | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c05e9ade779141..bd405225746e70 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -948,13 +948,14 @@ func (s *regAllocState) regalloc(f *Func) { if vi.spillUsed { // Use the spill location. v.SetArg(0, vi.spill) - b.Values = append(b.Values, v) } else { // No need to keep unspilled values live. // These are typically rematerializeable constants like nil, // or values of a variable that were modified since the last call. - v.Args[0].Uses-- + v.Op = OpCopy + v.SetArgs1(v.Args[1]) } + b.Values = append(b.Values, v) continue } regspec := opcodeTable[v.Op].reg diff --git a/test/fixedbugs/issue15277.go b/test/fixedbugs/issue15277.go index a3acc614bfc1ae..719c9a4f4a7aae 100644 --- a/test/fixedbugs/issue15277.go +++ b/test/fixedbugs/issue15277.go @@ -3,6 +3,7 @@ // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build amd64 package main From 1249197936aef58cb2296a3cd57b519ba3243042 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 May 2016 13:43:50 -0700 Subject: [PATCH 151/267] doc/go1.7: add runtime.KeepAlive Update #13347. Change-Id: I04bf317ed409478a859355f833d4a5e30db2b9c9 Reviewed-on: https://go-review.googlesource.com/23226 Reviewed-by: Ian Lance Taylor --- doc/go1.7.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.7.txt b/doc/go1.7.txt index d50f1f1032ec96..cf24eeffa019ab 100644 --- a/doc/go1.7.txt +++ b/doc/go1.7.txt @@ -27,6 +27,7 @@ API additions and behavior changes: crypto/tls: allow renegotiation to be handled by a client (CL 22475) runtime: support symbolic backtrace of C code in a cgo crash (CL 17761) runtime: add CallerFrames and Frames (CL 19869) +runtime: add KeepAlive (CL 23102) testing/quick: now generates nil values (CL 16470) net/http/httptest: ResponseRecorder supports trailer (CL 20047) (compat impact: issue 14928) net/url: support query string without values (CL 19931) From 1efec481d0997e260f4524d45d11cc35bed63f73 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 20:07:16 +0000 Subject: [PATCH 152/267] net/http: further restrict when Transport's automatic HTTP/2 happens Make the temporary, conservative restrictions from rev 79d9f48c in Go 1.6 permanent, and also don't do automatic TLS if the user configured a Dial or DialTLS hook. (Go 1.7 has Transport.Dialer instead, for tweaking dialing parameters) Fixes #14275 Change-Id: I5550d5c1e3a293e103eb4251a3685dc204a23941 Reviewed-on: https://go-review.googlesource.com/23222 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/transport.go | 13 ++++++------- src/net/http/transport_test.go | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 865dbdd50824e0..17e6270151901f 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -195,13 +195,12 @@ func (t *Transport) onceSetNextProtoDefaults() { // Transport. return } - if t.TLSClientConfig != nil { - // Be conservative for now (for Go 1.6) at least and - // don't automatically enable http2 if they've - // specified a custom TLS config. Let them opt-in - // themselves via http2.ConfigureTransport so we don't - // surprise them by modifying their tls.Config. - // Issue 14275. + if t.TLSClientConfig != nil || t.Dial != nil || t.DialTLS != nil { + // Be conservative and don't automatically enable + // http2 if they've specified a custom TLS config or + // custom dialers. Let them opt-in themselves via + // http2.ConfigureTransport so we don't surprise them + // by modifying their tls.Config. Issue 14275. return } if t.ExpectContinueTimeout != 0 && t != DefaultTransport { diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 48b1b309d330b2..ab05c31cb55501 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2986,6 +2986,21 @@ func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) { }, false) } +func TestTransportAutomaticHTTP2_Dial(t *testing.T) { + var d net.Dialer + testTransportAutoHTTP(t, &Transport{ + Dial: d.Dial, + }, false) +} + +func TestTransportAutomaticHTTP2_DialTLS(t *testing.T) { + testTransportAutoHTTP(t, &Transport{ + DialTLS: func(network, addr string) (net.Conn, error) { + panic("unused") + }, + }, false) +} + func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) { _, err := tr.RoundTrip(new(Request)) if err == nil { From d8bd7b24fcc72fb4117f7fc249ceaa79f69d4e00 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 17:59:12 +0000 Subject: [PATCH 153/267] net/http: update bundled x/net/http2 for Server context changes Updates x/net/http2 to golang.org/cl/23220 (http2: with Go 1.7 set Request.Context in ServeHTTP handlers) Fixes #15134 Change-Id: I73bac2601118614528f051e85dab51dc48e74f41 Reviewed-on: https://go-review.googlesource.com/23221 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Andrew Gerrand --- src/net/http/h2_bundle.go | 49 ++++++++++++++++++++++++++++++++------ src/net/http/serve_test.go | 32 ++++++++++++++++++------- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 21b10355a9d5b0..22047c582634c8 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1974,6 +1974,27 @@ func http2summarizeFrame(f http2Frame) string { return buf.String() } +type http2contextContext interface { + context.Context +} + +func http2serverConnBaseContext(c net.Conn, opts *http2ServeConnOpts) (ctx http2contextContext, cancel func()) { + ctx, cancel = context.WithCancel(context.Background()) + ctx = context.WithValue(ctx, LocalAddrContextKey, c.LocalAddr()) + if hs := opts.baseConfig(); hs != nil { + ctx = context.WithValue(ctx, ServerContextKey, hs) + } + return +} + +func http2contextWithCancel(ctx http2contextContext) (_ http2contextContext, cancel func()) { + return context.WithCancel(ctx) +} + +func http2requestWithContext(req *Request, ctx http2contextContext) *Request { + return req.WithContext(ctx) +} + type http2clientTrace httptrace.ClientTrace func http2reqContext(r *Request) context.Context { return r.Context() } @@ -2994,10 +3015,14 @@ func (o *http2ServeConnOpts) handler() Handler { // // The opts parameter is optional. If nil, default values are used. func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { + baseCtx, cancel := http2serverConnBaseContext(c, opts) + defer cancel() + sc := &http2serverConn{ srv: s, hs: opts.baseConfig(), conn: c, + baseCtx: baseCtx, remoteAddrStr: c.RemoteAddr().String(), bw: http2newBufferedWriter(c), handler: opts.handler(), @@ -3016,6 +3041,7 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { serveG: http2newGoroutineLock(), pushEnabled: true, } + sc.flow.add(http2initialWindowSize) sc.inflow.add(http2initialWindowSize) sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) @@ -3088,6 +3114,7 @@ type http2serverConn struct { conn net.Conn bw *http2bufferedWriter // writing to conn handler Handler + baseCtx http2contextContext framer *http2Framer doneServing chan struct{} // closed when serverConn.serve ends readFrameCh chan http2readFrameResult // written by serverConn.readFrames @@ -3151,10 +3178,12 @@ func (sc *http2serverConn) maxHeaderListSize() uint32 { // responseWriter's state field. type http2stream struct { // immutable: - sc *http2serverConn - id uint32 - body *http2pipe // non-nil if expecting DATA frames - cw http2closeWaiter // closed wait stream transitions to closed state + sc *http2serverConn + id uint32 + body *http2pipe // non-nil if expecting DATA frames + cw http2closeWaiter // closed wait stream transitions to closed state + ctx http2contextContext + cancelCtx func() // owned by serverConn's serve loop: bodyBytes int64 // body bytes seen so far @@ -3818,6 +3847,7 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error { } if st != nil { st.gotReset = true + st.cancelCtx() sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode}) } return nil @@ -3997,10 +4027,13 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { } sc.maxStreamID = id + ctx, cancelCtx := http2contextWithCancel(sc.baseCtx) st = &http2stream{ - sc: sc, - id: id, - state: http2stateOpen, + sc: sc, + id: id, + state: http2stateOpen, + ctx: ctx, + cancelCtx: cancelCtx, } if f.StreamEnded() { st.state = http2stateHalfClosedRemote @@ -4208,6 +4241,7 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead Body: body, Trailer: trailer, } + req = http2requestWithContext(req, st.ctx) if bodyOpen { buf := make([]byte, http2initialWindowSize) @@ -4250,6 +4284,7 @@ func (sc *http2serverConn) getRequestBodyBuf() []byte { func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) { didPanic := true defer func() { + rw.rws.stream.cancelCtx() if didPanic { e := recover() // Same as net/http: diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index e398c92638eb24..c32ff299029a49 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -4064,10 +4064,16 @@ func TestServerValidatesHeaders(t *testing.T) { } } -func TestServerRequestContextCancel_ServeHTTPDone(t *testing.T) { +func TestServerRequestContextCancel_ServeHTTPDone_h1(t *testing.T) { + testServerRequestContextCancel_ServeHTTPDone(t, h1Mode) +} +func TestServerRequestContextCancel_ServeHTTPDone_h2(t *testing.T) { + testServerRequestContextCancel_ServeHTTPDone(t, h2Mode) +} +func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) { defer afterTest(t) ctxc := make(chan context.Context, 1) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { ctx := r.Context() select { case <-ctx.Done(): @@ -4076,8 +4082,8 @@ func TestServerRequestContextCancel_ServeHTTPDone(t *testing.T) { } ctxc <- ctx })) - defer ts.Close() - res, err := Get(ts.URL) + defer cst.close() + res, err := cst.c.Get(cst.ts.URL) if err != nil { t.Fatal(err) } @@ -4130,9 +4136,15 @@ func TestServerRequestContextCancel_ConnClose(t *testing.T) { } } -func TestServerContext_ServerContextKey(t *testing.T) { +func TestServerContext_ServerContextKey_h1(t *testing.T) { + testServerContext_ServerContextKey(t, h1Mode) +} +func TestServerContext_ServerContextKey_h2(t *testing.T) { + testServerContext_ServerContextKey(t, h2Mode) +} +func testServerContext_ServerContextKey(t *testing.T, h2 bool) { defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { ctx := r.Context() got := ctx.Value(ServerContextKey) if _, ok := got.(*Server); !ok { @@ -4140,12 +4152,14 @@ func TestServerContext_ServerContextKey(t *testing.T) { } got = ctx.Value(LocalAddrContextKey) - if _, ok := got.(net.Addr); !ok { + if addr, ok := got.(net.Addr); !ok { t.Errorf("local addr value = %T; want net.Addr", got) + } else if fmt.Sprint(addr) != r.Host { + t.Errorf("local addr = %v; want %v", addr, r.Host) } })) - defer ts.Close() - res, err := Get(ts.URL) + defer cst.close() + res, err := cst.c.Get(cst.ts.URL) if err != nil { t.Fatal(err) } From ebbe4f8db76b947663cc535602054c84b01b080d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 15 Feb 2016 11:41:40 -0500 Subject: [PATCH 154/267] crypto/tls: Never resume sessions across different versions. Instead, decline the session and do a full handshake. The semantics of cross-version resume are unclear, and all major client implementations treat this as a fatal error. (This doesn't come up very much, mostly if the client does the browser version fallback without sharding the session cache.) See BoringSSL's bdf5e72f50e25f0e45e825c156168766d8442dde and OpenSSL's 9e189b9dc10786c755919e6792e923c584c918a1. Change-Id: I51ca95ac1691870dd0c148fd967739e2d4f58824 Reviewed-on: https://go-review.googlesource.com/21152 Reviewed-by: Adam Langley Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/crypto/tls/handshake_server.go | 6 +-- src/crypto/tls/handshake_server_test.go | 58 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 8e94f2143acbc4..cf617df19f5c00 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -284,10 +284,8 @@ func (hs *serverHandshakeState) checkForResumption() bool { return false } - if hs.sessionState.vers > hs.clientHello.vers { - return false - } - if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { + // Never resume a session for a different TLS version. + if c.vers != hs.sessionState.vers { return false } diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index fba81f619a6fe7..d878f9988949d7 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -399,6 +399,64 @@ func TestSCTHandshake(t *testing.T) { } } +func TestCrossVersionResume(t *testing.T) { + serverConfig := &Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + Certificates: testConfig.Certificates, + } + clientConfig := &Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + InsecureSkipVerify: true, + ClientSessionCache: NewLRUClientSessionCache(1), + ServerName: "servername", + } + + // Establish a session at TLS 1.1. + clientConfig.MaxVersion = VersionTLS11 + _, _, err := testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + + // The client session cache now contains a TLS 1.1 session. + state, _, err := testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if !state.DidResume { + t.Fatalf("handshake did not resume at the same version") + } + + // Test that the server will decline to resume at a lower version. + clientConfig.MaxVersion = VersionTLS10 + state, _, err = testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if state.DidResume { + t.Fatalf("handshake resumed at a lower version") + } + + // The client session cache now contains a TLS 1.0 session. + state, _, err = testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if !state.DidResume { + t.Fatalf("handshake did not resume at the same version") + } + + // Test that the server will decline to resume at a higher version. + clientConfig.MaxVersion = VersionTLS11 + state, _, err = testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if state.DidResume { + t.Fatalf("handshake resumed at a higher version") + } +} + // Note: see comment in handshake_test.go for details of how the reference // tests work. From 538537a28dc956f069b83e3f1966683901205331 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 May 2016 13:19:24 -0700 Subject: [PATCH 155/267] runtime: check only up to ptrdata bytes for pointers Fixes #14508. Change-Id: I237d0c5a79a73e6c97bdb2077d8ede613128b978 Reviewed-on: https://go-review.googlesource.com/23224 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- misc/cgo/errors/ptr.go | 24 ++++++++++++++++++++++++ src/runtime/cgocheck.go | 19 ++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/misc/cgo/errors/ptr.go b/misc/cgo/errors/ptr.go index b6cec8e10d0fe2..27eb78e36cfbc0 100644 --- a/misc/cgo/errors/ptr.go +++ b/misc/cgo/errors/ptr.go @@ -290,6 +290,30 @@ var ptrTests = []ptrTest{ }, fail: true, }, + { + // Don't check non-pointer data. + // Uses unsafe code to get a pointer we shouldn't check. + // Although we use unsafe, the uintptr represents an integer + // that happens to have the same representation as a pointer; + // that is, we are testing something that is not unsafe. + name: "ptrdata1", + c: `#include + void f(void* p) {}`, + imports: []string{"unsafe"}, + support: `type S struct { p *int; a [8*8]byte; u uintptr }`, + body: `i := 0; p := &S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f(unsafe.Pointer(q))`, + fail: false, + }, + { + // Like ptrdata1, but with a type that uses a GC program. + name: "ptrdata2", + c: `#include + void f(void* p) {}`, + imports: []string{"unsafe"}, + support: `type S struct { p *int; a [32769*8]byte; q *int; u uintptr }`, + body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`, + fail: false, + }, } func main() { diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go index d85d5fe5a8ba15..2d064145a415de 100644 --- a/src/runtime/cgocheck.go +++ b/src/runtime/cgocheck.go @@ -94,6 +94,14 @@ func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) { //go:nosplit //go:nowritebarrier func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { + // Anything past typ.ptrdata is not a pointer. + if typ.ptrdata <= off { + return + } + if ptrdataSize := typ.ptrdata - off; size > ptrdataSize { + size = ptrdataSize + } + if typ.kind&kindGCProg == 0 { cgoCheckBits(src, typ.gcdata, off, size) return @@ -184,7 +192,7 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) { // cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch // fall back to look for pointers in src using the type information. -// We only this when looking at a value on the stack when the type +// We only use this when looking at a value on the stack when the type // uses a GC program, because otherwise it's more efficient to use the // GC bits. This is called on the system stack. //go:nowritebarrier @@ -193,6 +201,15 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { if typ.kind&kindNoPointers != 0 { return } + + // Anything past typ.ptrdata is not a pointer. + if typ.ptrdata <= off { + return + } + if ptrdataSize := typ.ptrdata - off; size > ptrdataSize { + size = ptrdataSize + } + if typ.kind&kindGCProg == 0 { cgoCheckBits(src, typ.gcdata, off, size) return From c08436d1c897996055892882d23ce6778f3492f7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 May 2016 15:20:56 -0700 Subject: [PATCH 156/267] runtime: print PC, not the counter, for a cgo traceback Change-Id: I54ed7a26a753afb2d6a72080e1f50ce9fba7c183 Reviewed-on: https://go-review.googlesource.com/23228 Run-TryBot: Ian Lance Taylor Reviewed-by: Austin Clements TryBot-Result: Gobot Gobot --- src/runtime/traceback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 0e96a28945351b..eef34708031a66 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -1039,7 +1039,7 @@ func printOneCgoTraceback(pc uintptr, max int, arg *cgoSymbolizerArg) int { if arg.file != nil { print(gostringnocopy(arg.file), ":", arg.lineno, " ") } - print("pc=", hex(c), "\n") + print("pc=", hex(pc), "\n") c++ if arg.more == 0 { break From 5bcdd639331cd7f8d844fd38a674c4751423f938 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 May 2016 21:54:12 +0000 Subject: [PATCH 157/267] net: don't return io.EOF from zero byte reads Updates #15735 Change-Id: I42ab2345443bbaeaf935d683460fc2c941b7679c Reviewed-on: https://go-review.googlesource.com/23227 Reviewed-by: Ian Lance Taylor --- src/net/fd_unix.go | 8 +++++++ src/net/fd_windows.go | 4 +++- src/net/net_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go index 7ef10702ed8c08..0f80bc79ac270e 100644 --- a/src/net/fd_unix.go +++ b/src/net/fd_unix.go @@ -201,6 +201,14 @@ func (fd *netFD) Read(p []byte) (n int, err error) { return 0, err } defer fd.readUnlock() + if len(p) == 0 { + // If the caller wanted a zero byte read, return immediately + // without trying. (But after acquiring the readLock.) Otherwise + // syscall.Read returns 0, nil and eofError turns that into + // io.EOF. + // TODO(bradfitz): make it wait for readability? (Issue 15735) + return 0, nil + } if err := fd.pd.prepareRead(); err != nil { return 0, err } diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go index 49e79d6a950c04..b0b6769eb3cf74 100644 --- a/src/net/fd_windows.go +++ b/src/net/fd_windows.go @@ -427,7 +427,9 @@ func (fd *netFD) Read(buf []byte) (int, error) { if race.Enabled { race.Acquire(unsafe.Pointer(&ioSync)) } - err = fd.eofError(n, err) + if len(buf) != 0 { + err = fd.eofError(n, err) + } if _, ok := err.(syscall.Errno); ok { err = os.NewSyscallError("wsarecv", err) } diff --git a/src/net/net_test.go b/src/net/net_test.go index 94392928c2df60..b2f825daffc93c 100644 --- a/src/net/net_test.go +++ b/src/net/net_test.go @@ -360,3 +360,57 @@ func TestAcceptIgnoreAbortedConnRequest(t *testing.T) { t.Error(err) } } + +func TestZeroByteRead(t *testing.T) { + for _, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue + } + + ln, err := newLocalListener(network) + if err != nil { + t.Fatal(err) + } + connc := make(chan Conn, 1) + go func() { + defer ln.Close() + c, err := ln.Accept() + if err != nil { + t.Error(err) + } + connc <- c // might be nil + }() + c, err := Dial(network, ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + sc := <-connc + if sc == nil { + continue + } + defer sc.Close() + + if runtime.GOOS == "windows" { + // A zero byte read on Windows caused a wait for readability first. + // Rather than change that behavior, satisfy it in this test. + // See Issue 15735. + go io.WriteString(sc, "a") + } + + n, err := c.Read(nil) + if n != 0 || err != nil { + t.Errorf("%s: zero byte client read = %v, %v; want 0, nil", network, n, err) + } + + if runtime.GOOS == "windows" { + // Same as comment above. + go io.WriteString(c, "a") + } + n, err = sc.Read(nil) + if n != 0 || err != nil { + t.Errorf("%s: zero byte server read = %v, %v; want 0, nil", network, n, err) + } + } +} From 8d428ed218d2b65dbb4abbd9be870c95439a2b14 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 19 May 2016 12:04:10 +0900 Subject: [PATCH 158/267] net: don't return io.EOF from zero byte reads on Plan 9 Updates #15735. Fixes #15741. Change-Id: Ic4ad7e948e8c3ab5feffef89d7a37417f82722a1 Reviewed-on: https://go-review.googlesource.com/23199 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/fd_plan9.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go index 8e272b1eb85e53..7533232dc9b5eb 100644 --- a/src/net/fd_plan9.go +++ b/src/net/fd_plan9.go @@ -76,6 +76,9 @@ func (fd *netFD) Read(b []byte) (n int, err error) { return 0, err } defer fd.readUnlock() + if len(b) == 0 { + return 0, nil + } n, err = fd.data.Read(b) if isHangup(err) { err = io.EOF From 255e206b2bae9e7632043e08cf8cc0c7ce445c31 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 19 May 2016 02:13:36 +0000 Subject: [PATCH 159/267] net/http: update bundled http2 Updates x/net/http2 to git rev 5916dcb1 for: * http2, lex/httplex: make Transport reject bogus headers before sending https://golang.org/cl/23229 * http2: reject more trailer values https://golang.org/cl/23230 Fixes #14048 Fixes #14188 Change-Id: Iaa8beca6e005267a3e849a10013eb424a882f2bb Reviewed-on: https://go-review.googlesource.com/23234 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/go/build/deps_test.go | 1 + src/net/http/h2_bundle.go | 216 +++++++----------- src/net/http/http.go | 6 + src/net/http/server.go | 8 +- src/net/http/transfer.go | 6 +- src/net/http/transport.go | 6 +- .../golang.org/x/net/lex/httplex/httplex.go} | 63 +++-- .../x/net/lex/httplex/httplex_test.go} | 6 +- 8 files changed, 152 insertions(+), 160 deletions(-) rename src/{net/http/lex.go => vendor/golang.org/x/net/lex/httplex/httplex.go} (73%) rename src/{net/http/lex_test.go => vendor/golang.org/x/net/lex/httplex/httplex_test.go} (94%) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 958e410dd95120..f9a428edd42b45 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -379,6 +379,7 @@ var pkgDeps = map[string][]string{ "mime/multipart", "runtime/debug", "net/http/internal", "golang.org/x/net/http2/hpack", + "golang.org/x/net/lex/httplex", "internal/nettrace", "net/http/httptrace", }, diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 22047c582634c8..6f7fd382ea088b 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -26,6 +26,7 @@ import ( "errors" "fmt" "golang.org/x/net/http2/hpack" + "golang.org/x/net/lex/httplex" "io" "io/ioutil" "log" @@ -1864,7 +1865,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr hdec.SetEmitEnabled(true) hdec.SetMaxStringLength(fr.maxHeaderStringLen()) hdec.SetEmitFunc(func(hf hpack.HeaderField) { - if !http2validHeaderFieldValue(hf.Value) { + if !httplex.ValidHeaderFieldValue(hf.Value) { invalid = http2headerFieldValueError(hf.Value) } isPseudo := strings.HasPrefix(hf.Name, ":") @@ -1874,7 +1875,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr } } else { sawRegular = true - if !http2validHeaderFieldName(hf.Name) { + if !http2validWireHeaderFieldName(hf.Name) { invalid = http2headerFieldNameError(hf.Name) } } @@ -2397,58 +2398,23 @@ var ( http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value") ) -// validHeaderFieldName reports whether v is a valid header field name (key). -// RFC 7230 says: -// header-field = field-name ":" OWS field-value OWS -// field-name = token -// token = 1*tchar -// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / -// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +// validWireHeaderFieldName reports whether v is a valid header field +// name (key). See httplex.ValidHeaderName for the base rules. +// // Further, http2 says: // "Just as in HTTP/1.x, header field names are strings of ASCII // characters that are compared in a case-insensitive // fashion. However, header field names MUST be converted to // lowercase prior to their encoding in HTTP/2. " -func http2validHeaderFieldName(v string) bool { +func http2validWireHeaderFieldName(v string) bool { if len(v) == 0 { return false } for _, r := range v { - if int(r) >= len(http2isTokenTable) || ('A' <= r && r <= 'Z') { + if !httplex.IsTokenRune(r) { return false } - if !http2isTokenTable[byte(r)] { - return false - } - } - return true -} - -// validHeaderFieldValue reports whether v is a valid header field value. -// -// RFC 7230 says: -// field-value = *( field-content / obs-fold ) -// obj-fold = N/A to http2, and deprecated -// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] -// field-vchar = VCHAR / obs-text -// obs-text = %x80-FF -// VCHAR = "any visible [USASCII] character" -// -// http2 further says: "Similarly, HTTP/2 allows header field values -// that are not valid. While most of the values that can be encoded -// will not alter header field parsing, carriage return (CR, ASCII -// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII -// 0x0) might be exploited by an attacker if they are translated -// verbatim. Any request or response that contains a character not -// permitted in a header field value MUST be treated as malformed -// (Section 8.1.2.6). Valid characters are defined by the -// field-content ABNF rule in Section 3.2 of [RFC7230]." -// -// This function does not (yet?) properly handle the rejection of -// strings that begin or end with SP or HTAB. -func http2validHeaderFieldValue(v string) bool { - for i := 0; i < len(v); i++ { - if b := v[i]; b < ' ' && b != '\t' || b == 0x7f { + if 'A' <= r && r <= 'Z' { return false } } @@ -2579,86 +2545,6 @@ func (e *http2httpError) Temporary() bool { return true } var http2errTimeout error = &http2httpError{msg: "http2: timeout awaiting response headers", timeout: true} -var http2isTokenTable = [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, -} - type http2connectionStater interface { ConnectionState() tls.ConnectionState } @@ -4103,6 +3989,10 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error { if st.trailer != nil { for _, hf := range f.RegularFields() { key := sc.canonicalHeader(hf.Name) + if !http2ValidTrailerHeader(key) { + + return http2StreamError{st.id, http2ErrCodeProtocol} + } st.trailer[key] = append(st.trailer[key], hf.Value) } } @@ -4508,9 +4398,9 @@ func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailer // written in the trailers at the end of the response. func (rws *http2responseWriterState) declareTrailer(k string) { k = CanonicalHeaderKey(k) - switch k { - case "Transfer-Encoding", "Content-Length", "Trailer": + if !http2ValidTrailerHeader(k) { + rws.conn.logf("ignoring invalid trailer %q", k) return } if !http2strSliceContains(rws.trailers, k) { @@ -4831,6 +4721,41 @@ func http2new400Handler(err error) HandlerFunc { } } +// ValidTrailerHeader reports whether name is a valid header field name to appear +// in trailers. +// See: http://tools.ietf.org/html/rfc7230#section-4.1.2 +func http2ValidTrailerHeader(name string) bool { + name = CanonicalHeaderKey(name) + if strings.HasPrefix(name, "If-") || http2badTrailer[name] { + return false + } + return true +} + +var http2badTrailer = map[string]bool{ + "Authorization": true, + "Cache-Control": true, + "Connection": true, + "Content-Encoding": true, + "Content-Length": true, + "Content-Range": true, + "Content-Type": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Max-Forwards": true, + "Pragma": true, + "Proxy-Authenticate": true, + "Proxy-Authorization": true, + "Proxy-Connection": true, + "Range": true, + "Realm": true, + "Te": true, + "Trailer": true, + "Transfer-Encoding": true, + "Www-Authenticate": true, +} + const ( // transportDefaultConnFlow is how many connection-level flow control // tokens we give the server at start-up, past the default 64k. @@ -5423,20 +5348,28 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { return nil, http2errClientConnUnusable } - cs := cc.newStream() - cs.req = req - cs.trace = http2requestTrace(req) - hasBody := body != nil - + // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? + var requestedGzip bool if !cc.t.disableCompression() && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" && req.Method != "HEAD" { - cs.requestedGzip = true + requestedGzip = true } - hdrs := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen) + hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen) + if err != nil { + cc.mu.Unlock() + return nil, err + } + + cs := cc.newStream() + cs.req = req + cs.trace = http2requestTrace(req) + hasBody := body != nil + cs.requestedGzip = requestedGzip + cc.wmu.Lock() endStream := !hasBody && !hasTrailers werr := cc.writeHeaders(cs.ID, endStream, hdrs) @@ -5689,7 +5622,7 @@ type http2badStringError struct { func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } // requires cc.mu be held. -func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) []byte { +func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { cc.hbuf.Reset() host := req.Host @@ -5697,6 +5630,17 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail host = req.URL.Host } + for k, vv := range req.Header { + if !httplex.ValidHeaderFieldName(k) { + return nil, fmt.Errorf("invalid HTTP header name %q", k) + } + for _, v := range vv { + if !httplex.ValidHeaderFieldValue(v) { + return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k) + } + } + } + cc.writeHeader(":authority", host) cc.writeHeader(":method", req.Method) if req.Method != "CONNECT" { @@ -5741,7 +5685,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail if !didUA { cc.writeHeader("user-agent", http2defaultUserAgent) } - return cc.hbuf.Bytes() + return cc.hbuf.Bytes(), nil } // shouldSendReqContentLength reports whether the http2.Transport should send @@ -6622,13 +6566,13 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) { for _, k := range keys { vv := h[k] k = http2lowerHeader(k) - if !http2validHeaderFieldName(k) { + if !http2validWireHeaderFieldName(k) { continue } isTE := k == "transfer-encoding" for _, v := range vv { - if !http2validHeaderFieldValue(v) { + if !httplex.ValidHeaderFieldValue(v) { continue } diff --git a/src/net/http/http.go b/src/net/http/http.go index a121628632f99a..4d088a5bb1c812 100644 --- a/src/net/http/http.go +++ b/src/net/http/http.go @@ -6,6 +6,8 @@ package http import ( "strings" + + "golang.org/x/net/lex/httplex" ) // maxInt64 is the effective "infinite" value for the Server and @@ -35,3 +37,7 @@ func removeEmptyPort(host string) string { } return host } + +func isNotToken(r rune) bool { + return !httplex.IsTokenRune(r) +} diff --git a/src/net/http/server.go b/src/net/http/server.go index d4e38b6ad09420..1a8c0fc6cc27ba 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -27,6 +27,8 @@ import ( "sync" "sync/atomic" "time" + + "golang.org/x/net/lex/httplex" ) // Errors used by the HTTP server. @@ -783,15 +785,15 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) { if len(hosts) > 1 { return nil, badRequestError("too many Host headers") } - if len(hosts) == 1 && !validHostHeader(hosts[0]) { + if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) { return nil, badRequestError("malformed Host header") } for k, vv := range req.Header { - if !validHeaderName(k) { + if !httplex.ValidHeaderFieldName(k) { return nil, badRequestError("invalid header name") } for _, v := range vv { - if !validHeaderValue(v) { + if !httplex.ValidHeaderFieldValue(v) { return nil, badRequestError("invalid header value") } } diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index 501e4be08cba59..b27ace638a191f 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -17,6 +17,8 @@ import ( "strconv" "strings" "sync" + + "golang.org/x/net/lex/httplex" ) // ErrLineTooLong is returned when reading request or response bodies @@ -561,9 +563,9 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool { } conv := header["Connection"] - hasClose := headerValuesContainsToken(conv, "close") + hasClose := httplex.HeaderValuesContainsToken(conv, "close") if major == 1 && minor == 0 { - return hasClose || !headerValuesContainsToken(conv, "keep-alive") + return hasClose || !httplex.HeaderValuesContainsToken(conv, "keep-alive") } if hasClose && removeCloseHeader { diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 17e6270151901f..777501f5bd42bd 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -26,6 +26,8 @@ import ( "strings" "sync" "time" + + "golang.org/x/net/lex/httplex" ) // DefaultTransport is the default implementation of Transport and is @@ -324,11 +326,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { isHTTP := scheme == "http" || scheme == "https" if isHTTP { for k, vv := range req.Header { - if !validHeaderName(k) { + if !httplex.ValidHeaderFieldName(k) { return nil, fmt.Errorf("net/http: invalid header field name %q", k) } for _, v := range vv { - if !validHeaderValue(v) { + if !httplex.ValidHeaderFieldValue(v) { return nil, fmt.Errorf("net/http: invalid header field value %q for key %v", v, k) } } diff --git a/src/net/http/lex.go b/src/vendor/golang.org/x/net/lex/httplex/httplex.go similarity index 73% rename from src/net/http/lex.go rename to src/vendor/golang.org/x/net/lex/httplex/httplex.go index 63d14ec2ecca5b..bd0ec24f444365 100644 --- a/src/net/http/lex.go +++ b/src/vendor/golang.org/x/net/lex/httplex/httplex.go @@ -1,16 +1,19 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// 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 http +// Package httplex contains rules around lexical matters of various +// HTTP-related specifications. +// +// This package is shared by the standard library (which vendors it) +// and x/net/http2. It comes with no API stability promise. +package httplex import ( "strings" "unicode/utf8" ) -// This file deals with lexical matters of HTTP - var isTokenTable = [127]bool{ '!': true, '#': true, @@ -91,18 +94,18 @@ var isTokenTable = [127]bool{ '~': true, } -func isToken(r rune) bool { +func IsTokenRune(r rune) bool { i := int(r) return i < len(isTokenTable) && isTokenTable[i] } func isNotToken(r rune) bool { - return !isToken(r) + return !IsTokenRune(r) } -// headerValuesContainsToken reports whether any string in values +// HeaderValuesContainsToken reports whether any string in values // contains the provided token, ASCII case-insensitively. -func headerValuesContainsToken(values []string, token string) bool { +func HeaderValuesContainsToken(values []string, token string) bool { for _, v := range values { if headerValueContainsToken(v, token) { return true @@ -182,20 +185,31 @@ func isCTL(b byte) bool { return b < ' ' || b == del } -func validHeaderName(v string) bool { +// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name. +// HTTP/2 imposes the additional restriction that uppercase ASCII +// letters are not allowed. +// +// RFC 7230 says: +// header-field = field-name ":" OWS field-value OWS +// field-name = token +// token = 1*tchar +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +func ValidHeaderFieldName(v string) bool { if len(v) == 0 { return false } for _, r := range v { - if !isToken(r) { + if !IsTokenRune(r) { return false } } return true } -func validHostHeader(h string) bool { - // The latests spec is actually this: +// ValidHostHeader reports whether h is a valid host header. +func ValidHostHeader(h string) bool { + // The latest spec is actually this: // // http://tools.ietf.org/html/rfc7230#section-5.4 // Host = uri-host [ ":" port ] @@ -250,7 +264,7 @@ var validHostByte = [256]bool{ '~': true, // unreserved } -// validHeaderValue reports whether v is a valid "field-value" according to +// ValidHeaderFieldValue reports whether v is a valid "field-value" according to // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 : // // message-header = field-name ":" [ field-value ] @@ -266,7 +280,28 @@ var validHostByte = [256]bool{ // LWS = [CRLF] 1*( SP | HT ) // CTL = -func validHeaderValue(v string) bool { +// +// RFC 7230 says: +// field-value = *( field-content / obs-fold ) +// obj-fold = N/A to http2, and deprecated +// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +// field-vchar = VCHAR / obs-text +// obs-text = %x80-FF +// VCHAR = "any visible [USASCII] character" +// +// http2 further says: "Similarly, HTTP/2 allows header field values +// that are not valid. While most of the values that can be encoded +// will not alter header field parsing, carriage return (CR, ASCII +// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII +// 0x0) might be exploited by an attacker if they are translated +// verbatim. Any request or response that contains a character not +// permitted in a header field value MUST be treated as malformed +// (Section 8.1.2.6). Valid characters are defined by the +// field-content ABNF rule in Section 3.2 of [RFC7230]." +// +// This function does not (yet?) properly handle the rejection of +// strings that begin or end with SP or HTAB. +func ValidHeaderFieldValue(v string) bool { for i := 0; i < len(v); i++ { b := v[i] if isCTL(b) && !isLWS(b) { diff --git a/src/net/http/lex_test.go b/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go similarity index 94% rename from src/net/http/lex_test.go rename to src/vendor/golang.org/x/net/lex/httplex/httplex_test.go index 986fda17dcd6e4..c4ace1991b35dc 100644 --- a/src/net/http/lex_test.go +++ b/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package http +package httplex import ( "testing" @@ -24,7 +24,7 @@ func TestIsToken(t *testing.T) { for i := 0; i <= 130; i++ { r := rune(i) expected := isChar(r) && !isCtl(r) && !isSeparator(r) - if isToken(r) != expected { + if IsTokenRune(r) != expected { t.Errorf("isToken(0x%x) = %v", r, !expected) } } @@ -93,7 +93,7 @@ func TestHeaderValuesContainsToken(t *testing.T) { }, } for _, tt := range tests { - got := headerValuesContainsToken(tt.vals, tt.token) + got := HeaderValuesContainsToken(tt.vals, tt.token) if got != tt.want { t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want) } From 2a12035f8ec18f0a577853fda78faf2826397131 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 18 May 2016 18:44:46 -0700 Subject: [PATCH 160/267] expvar: slightly expand documentation for Var's String method Fixes #15088. Change-Id: I7727829a4062e15c0e5e3beff4d0bfc1fa327b0f Reviewed-on: https://go-review.googlesource.com/23232 Reviewed-by: Andrew Gerrand Reviewed-by: Brad Fitzpatrick --- src/expvar/expvar.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go index b7ea433014b9dc..d5465c518f81d9 100644 --- a/src/expvar/expvar.go +++ b/src/expvar/expvar.go @@ -39,6 +39,8 @@ import ( // Var is an abstract type for all exported variables. type Var interface { // String returns a valid JSON value for the variable. + // Types with String methods that do not return valid JSON + // (such as time.Time) must not be used as a Var. String() string } From 1f7a0d4b5ec7ef94b96755e9b95168abf86e9d71 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 16 May 2016 15:39:43 -0700 Subject: [PATCH 161/267] runtime: don't do a plain throw when throwsplit == true The test case in #15639 somehow causes an invalid syscall frame. The failure is obscured because the throw occurs when throwsplit == true, which causes a "stack split at bad time" error when trying to print the throw message. This CL fixes the "stack split at bad time" by using systemstack. No test because there shouldn't be any way to trigger this error anyhow. Update #15639. Change-Id: I4240f3fd01bdc3c112f3ffd1316b68504222d9e1 Reviewed-on: https://go-review.googlesource.com/23153 Run-TryBot: Ian Lance Taylor Reviewed-by: Austin Clements --- src/runtime/proc.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index d7e51d7deb872a..15dcb95c9c6960 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -2445,7 +2445,12 @@ func exitsyscall(dummy int32) { _g_.m.locks++ // see comment in entersyscall if getcallersp(unsafe.Pointer(&dummy)) > _g_.syscallsp { - throw("exitsyscall: syscall frame is no longer valid") + // throw calls print which may try to grow the stack, + // but throwsplit == true so the stack can not be grown; + // use systemstack to avoid that possible problem. + systemstack(func() { + throw("exitsyscall: syscall frame is no longer valid") + }) } _g_.waitsince = 0 From 086d7b0e9e34555f32248c9242b641273a32bc7e Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 19 May 2016 17:36:47 +0900 Subject: [PATCH 162/267] net: deflake TestDialerDualStackFDLeak Fixes #14717. Updates #15157. Change-Id: I7238b4fe39f3670c2dfe09b3a3df51a982f261ed Reviewed-on: https://go-review.googlesource.com/23244 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/dial_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 93cffca93d2689..a07c5850e11408 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -128,13 +128,16 @@ func TestDialerDualStackFDLeak(t *testing.T) { t.Skipf("%s does not have full support of socktest", runtime.GOOS) case "windows": t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) - case "openbsd": - testenv.SkipFlaky(t, 15157) } if !supportsIPv4 || !supportsIPv6 { t.Skip("both IPv4 and IPv6 are required") } + closedPortDelay, expectClosedPortDelay := dialClosedPort() + if closedPortDelay > expectClosedPortDelay { + t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) + } + before := sw.Sockets() origTestHookLookupIP := testHookLookupIP defer func() { testHookLookupIP = origTestHookLookupIP }() @@ -163,7 +166,7 @@ func TestDialerDualStackFDLeak(t *testing.T) { const N = 10 var wg sync.WaitGroup wg.Add(N) - d := &Dialer{DualStack: true, Timeout: 100 * time.Millisecond} + d := &Dialer{DualStack: true, Timeout: 100*time.Millisecond + closedPortDelay} for i := 0; i < N; i++ { go func() { defer wg.Done() From 1ab9428eec6cd1595de571aac4c093645a6629d0 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 19 May 2016 06:15:18 +0900 Subject: [PATCH 163/267] net: deflake TestDialerDualStack Fixes #15316. Fixes #15574. Change-Id: I3ec8bffd35b9e5123de4be983a53fc0b8c2a0895 Reviewed-on: https://go-review.googlesource.com/23242 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/dial_test.go | 24 +++++------------------- src/net/mockserver_test.go | 38 +++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index a07c5850e11408..53656770112a3a 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -151,10 +151,7 @@ func TestDialerDualStackFDLeak(t *testing.T) { c.Close() } } - dss, err := newDualStackServer([]streamListener{ - {network: "tcp4", address: "127.0.0.1"}, - {network: "tcp6", address: "::1"}, - }) + dss, err := newDualStackServer() if err != nil { t.Fatal(err) } @@ -329,10 +326,7 @@ func TestDialParallel(t *testing.T) { } for i, tt := range testCases { - dss, err := newDualStackServer([]streamListener{ - {network: "tcp4", address: "127.0.0.1"}, - {network: "tcp6", address: "::1"}, - }) + dss, err := newDualStackServer() if err != nil { t.Fatal(err) } @@ -449,9 +443,7 @@ func TestDialerFallbackDelay(t *testing.T) { c.Close() } } - dss, err := newDualStackServer([]streamListener{ - {network: "tcp", address: "127.0.0.1"}, - }) + dss, err := newDualStackServer() if err != nil { t.Fatal(err) } @@ -504,10 +496,7 @@ func TestDialParallelSpuriousConnection(t *testing.T) { c.Close() wg.Done() } - dss, err := newDualStackServer([]streamListener{ - {network: "tcp4", address: "127.0.0.1"}, - {network: "tcp6", address: "::1"}, - }) + dss, err := newDualStackServer() if err != nil { t.Fatal(err) } @@ -733,10 +722,7 @@ func TestDialerDualStack(t *testing.T) { var timeout = 150*time.Millisecond + closedPortDelay for _, dualstack := range []bool{false, true} { - dss, err := newDualStackServer([]streamListener{ - {network: "tcp4", address: "127.0.0.1"}, - {network: "tcp6", address: "::1"}, - }) + dss, err := newDualStackServer() if err != nil { t.Fatal(err) } diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go index b67dd916506043..766de6a815b9df 100644 --- a/src/net/mockserver_test.go +++ b/src/net/mockserver_test.go @@ -184,28 +184,24 @@ func (dss *dualStackServer) teardown() error { return nil } -func newDualStackServer(lns []streamListener) (*dualStackServer, error) { - dss := &dualStackServer{lns: lns, port: "0"} - for i := range dss.lns { - ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port)) - if err != nil { - for _, ln := range dss.lns[:i] { - ln.Listener.Close() - } - return nil, err - } - dss.lns[i].Listener = ln - dss.lns[i].done = make(chan bool) - if dss.port == "0" { - if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil { - for _, ln := range dss.lns { - ln.Listener.Close() - } - return nil, err - } - } +func newDualStackServer() (*dualStackServer, error) { + lns, err := newDualStackListener() + if err != nil { + return nil, err + } + _, port, err := SplitHostPort(lns[0].Addr().String()) + if err != nil { + lns[0].Close() + lns[1].Close() + return nil, err } - return dss, nil + return &dualStackServer{ + lns: []streamListener{ + {network: "tcp4", address: lns[0].Addr().String(), Listener: lns[0], done: make(chan bool)}, + {network: "tcp6", address: lns[1].Addr().String(), Listener: lns[1], done: make(chan bool)}, + }, + port: port, + }, nil } func transponder(ln Listener, ch chan<- error) { From d603c27c6b462f044a7079ce5113d90bb3ca4814 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 18 May 2016 13:04:00 -0700 Subject: [PATCH 164/267] cmd/compile: large ptr literals must escape They get rewritten to NEWs, and they must be marked as escaping so walk doesn't try to allocate them back onto the stack. Fixes #15733 Change-Id: I433033e737c3de51a9e83a5a273168dbc9110b74 Reviewed-on: https://go-review.googlesource.com/23223 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/esc.go | 2 +- test/fixedbugs/issue15733.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue15733.go diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index bc22dfacc0f713..553dde8bf99cb9 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -640,7 +640,7 @@ func esc(e *EscState, n *Node, up *Node) { // "Big" conditions that were scattered around in walk have been gathered here if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize || - n.Op == ONEW && n.Type.Elem().Width >= 1<<16 || + (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 || n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { if Debug['m'] > 2 { Warnl(n.Lineno, "%v is too large for stack", n) diff --git a/test/fixedbugs/issue15733.go b/test/fixedbugs/issue15733.go new file mode 100644 index 00000000000000..8f609e634dd817 --- /dev/null +++ b/test/fixedbugs/issue15733.go @@ -0,0 +1,23 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type S struct { + a [1 << 16]byte +} + +func f1() { + p := &S{} + _ = p +} + +type T [1 << 16]byte + +func f2() { + p := &T{} + _ = p +} From 0dcd330bc8ab19db15b4517b80e940cf154071bc Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 18 May 2016 23:39:23 +1000 Subject: [PATCH 165/267] runtime/cgo: make cgo work with openbsd ABI changes OpenBSD 6.0 (due out November 2016) will support PT_TLS, which will allow for the OpenBSD cgo pthread_create() workaround to be removed. However, in order for Go to continue working on supported OpenBSD releases (the current release and the previous release - 5.9 and 6.0, once 6.0 is released), we cannot enable PT_TLS immediately. Instead, adjust the existing code so that it works with the previous TCB allocation and the new TIB allocation. This allows the same Go runtime to work on 5.8, 5.9 and later 6.0. Once OpenBSD 5.9 is no longer supported (May 2017, when 6.1 is released), PT_TLS can be enabled and the additional cgo runtime code removed. Change-Id: I3eed5ec593d80eea78c6656cb12557004b2c0c9a Reviewed-on: https://go-review.googlesource.com/23197 Reviewed-by: Ian Lance Taylor Run-TryBot: Joel Sing TryBot-Result: Gobot Gobot --- src/runtime/cgo/gcc_openbsd_386.c | 42 ++++++++++++++++++++++------- src/runtime/cgo/gcc_openbsd_amd64.c | 41 +++++++++++++++++++++------- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c index 22941a4c6d458f..1bc61ff7087bf9 100644 --- a/src/runtime/cgo/gcc_openbsd_386.c +++ b/src/runtime/cgo/gcc_openbsd_386.c @@ -13,9 +13,15 @@ static void* threadentry(void*); static void (*setg_gcc)(void*); -// TCB_SIZE is sizeof(struct thread_control_block), -// as defined in /usr/src/lib/librthread/tcb.h +// TCB_SIZE is sizeof(struct thread_control_block), as defined in +// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier. #define TCB_SIZE (4 * sizeof(void *)) + +// TIB_SIZE is sizeof(struct tib), as defined in +// /usr/include/tib.h on OpenBSD 6.0 and later. +#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int)) + +// TLS_SIZE is the size of TLS needed for Go. #define TLS_SIZE (2 * sizeof(void *)) void *__get_tcb(void); @@ -29,25 +35,38 @@ struct thread_args { void *arg; }; +static int has_tib = 0; + static void tcb_fixup(int mainthread) { - void *newtcb, *oldtcb; + void *tls, *newtcb, *oldtcb; + size_t tls_size, tcb_size; + + // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is + // no longer supported. // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result, // we need to allocate our own TLS space while preserving the existing - // TCB that has been setup via librthread. + // TCB or TIB that has been setup via librthread. - newtcb = malloc(TCB_SIZE + TLS_SIZE); - if(newtcb == NULL) + tcb_size = has_tib ? TIB_SIZE : TCB_SIZE; + tls_size = TLS_SIZE + tcb_size; + tls = malloc(tls_size); + if(tls == NULL) abort(); // The signal trampoline expects the TLS slots to be zeroed. - bzero(newtcb, TLS_SIZE); + bzero(tls, TLS_SIZE); oldtcb = __get_tcb(); - bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); - __set_tcb(newtcb + TLS_SIZE); + newtcb = tls + TLS_SIZE; + bcopy(oldtcb, newtcb, tcb_size); + if(has_tib) { + // Fix up self pointer. + *(uintptr_t *)(newtcb) = (uintptr_t)newtcb; + } + __set_tcb(newtcb); // NOTE(jsing, minux): we can't free oldtcb without causing double-free // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD @@ -79,6 +98,10 @@ static void init_pthread_wrapper(void) { fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); abort(); } + // _rthread_init is hidden in OpenBSD librthread that has TIB. + if(dlsym(handle, "_rthread_init") == NULL) { + has_tib = 1; + } dlclose(handle); } @@ -144,6 +167,7 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. ts->g->stackhi = size; err = sys_pthread_create(&p, &attr, threadentry, ts); diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c index e84fe6c18b035f..4d4d14314c790b 100644 --- a/src/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/runtime/cgo/gcc_openbsd_amd64.c @@ -13,9 +13,15 @@ static void* threadentry(void*); static void (*setg_gcc)(void*); -// TCB_SIZE is sizeof(struct thread_control_block), -// as defined in /usr/src/lib/librthread/tcb.h +// TCB_SIZE is sizeof(struct thread_control_block), as defined in +// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier. #define TCB_SIZE (4 * sizeof(void *)) + +// TIB_SIZE is sizeof(struct tib), as defined in +// /usr/include/tib.h on OpenBSD 6.0 and later. +#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int)) + +// TLS_SIZE is the size of TLS needed for Go. #define TLS_SIZE (2 * sizeof(void *)) void *__get_tcb(void); @@ -29,25 +35,38 @@ struct thread_args { void *arg; }; +static int has_tib = 0; + static void tcb_fixup(int mainthread) { - void *newtcb, *oldtcb; + void *tls, *newtcb, *oldtcb; + size_t tls_size, tcb_size; + + // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is + // no longer supported. // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result, // we need to allocate our own TLS space while preserving the existing - // TCB that has been setup via librthread. + // TCB or TIB that has been setup via librthread. - newtcb = malloc(TCB_SIZE + TLS_SIZE); - if(newtcb == NULL) + tcb_size = has_tib ? TIB_SIZE : TCB_SIZE; + tls_size = TLS_SIZE + tcb_size; + tls = malloc(tls_size); + if(tls == NULL) abort(); // The signal trampoline expects the TLS slots to be zeroed. - bzero(newtcb, TLS_SIZE); + bzero(tls, TLS_SIZE); oldtcb = __get_tcb(); - bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); - __set_tcb(newtcb + TLS_SIZE); + newtcb = tls + TLS_SIZE; + bcopy(oldtcb, newtcb, tcb_size); + if(has_tib) { + // Fix up self pointer. + *(uintptr_t *)(newtcb) = (uintptr_t)newtcb; + } + __set_tcb(newtcb); // NOTE(jsing, minux): we can't free oldtcb without causing double-free // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD @@ -79,6 +98,10 @@ static void init_pthread_wrapper(void) { fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); abort(); } + // _rthread_init is hidden in OpenBSD librthread that has TIB. + if(dlsym(handle, "_rthread_init") == NULL) { + has_tib = 1; + } dlclose(handle); } From 79ba1e44c7c2d7ff186f9ac142a85869f352f0f6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 19 May 2016 10:07:41 -0700 Subject: [PATCH 166/267] cmd/cgo: mark stub functions as no_sanitize_thread When the generated stub functions write back the results to the stack, they can in some cases be writing to the same memory on the g0 stack. There is no race here (assuming there is no race in the Go code), but the thread sanitizer does not know that. Turn off the thread sanitizer for the stub functions to prevent false positive warnings. Current clang suggests the no_sanitize("thread") attribute, but that does not work with clang 3.6 or GCC. clang 3.6, GCC, and current clang all support the no_sanitize_thread attribute, so use that unconditionally. The test case and first version of the patch are from Dmitriy Vyukov. Change-Id: I80ce92824c6c8cf88ea0fe44f21cf50cf62474c9 Reviewed-on: https://go-review.googlesource.com/23252 Run-TryBot: Ian Lance Taylor Reviewed-by: Dmitry Vyukov TryBot-Result: Gobot Gobot --- misc/cgo/testsanitizers/test.bash | 10 ++++++++ misc/cgo/testsanitizers/tsan3.go | 40 +++++++++++++++++++++++++++++++ src/cmd/cgo/out.go | 8 ++++++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 misc/cgo/testsanitizers/tsan3.go diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash index 76628abaff8741..8718815d3e19c2 100755 --- a/misc/cgo/testsanitizers/test.bash +++ b/misc/cgo/testsanitizers/test.bash @@ -134,6 +134,16 @@ if test "$tsan" = "yes"; then status=1 fi + if ! go run tsan3.go 2>$err; then + cat $err + echo "FAIL: tsan3" + status=1 + elif grep -i warning $err >/dev/null 2>&1; then + cat $err + echo "FAIL: tsan3" + status=1 + fi + rm -f $err fi diff --git a/misc/cgo/testsanitizers/tsan3.go b/misc/cgo/testsanitizers/tsan3.go new file mode 100644 index 00000000000000..87f6c80f1b18d5 --- /dev/null +++ b/misc/cgo/testsanitizers/tsan3.go @@ -0,0 +1,40 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// The stubs for the C functions read and write the same slot on the +// g0 stack when copying arguments in and out. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +int Func1() { + return 0; +} + +void Func2(int x) { + (void)x; +} +*/ +import "C" + +func main() { + const N = 10000 + done := make(chan bool, N) + for i := 0; i < N; i++ { + go func() { + C.Func1() + done <- true + }() + go func() { + C.Func2(0) + done <- true + }() + } + for i := 0; i < 2*N; i++ { + <-done + } +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 265a3bbe6f71c4..256b059e57211b 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -560,6 +560,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Gcc wrapper unpacks the C argument struct // and calls the actual C function. + fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n") if n.AddError { fmt.Fprintf(fgcc, "int\n") } else { @@ -635,6 +636,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // wrapper, we can't refer to the function, since the reference is in // a different file. func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { + fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n") if t := n.FuncType.Result; t != nil { fmt.Fprintf(fgcc, "%s\n", t.C.String()) } else { @@ -817,6 +819,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcch, "\nextern %s;\n", s) fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName) + fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD") fmt.Fprintf(fgcc, "\n%s\n", s) fmt.Fprintf(fgcc, "{\n") fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n") @@ -1020,7 +1023,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) fmt.Fprint(fgcc, "\n") - fmt.Fprint(fgcc, "\n") + fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n") fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) if resultCount > 0 { fmt.Fprintf(fgcc, "\t%s r;\n", cRet) @@ -1304,11 +1307,14 @@ extern char* _cgo_topofstack(void); // Prologue defining TSAN functions in C. const noTsanProlog = ` +#define CGO_NO_SANITIZE_THREAD #define _cgo_tsan_acquire() #define _cgo_tsan_release() ` const yesTsanProlog = ` +#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread)) + long long _cgo_sync __attribute__ ((common)); extern void __tsan_acquire(void*); From 91740582c3ec1e57621cbb0ec0f9163431f1b688 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 17 May 2016 18:21:54 -0400 Subject: [PATCH 167/267] runtime: add 'next' flag to ready Currently ready always puts the readied goroutine in runnext. We're going to have to change this for some uses, so add a flag for whether or not to use runnext. For now we always pass true so this is a no-op change. For #15706. Change-Id: Iaa66d8355ccfe4bbe347570cc1b1878c70fa25df Reviewed-on: https://go-review.googlesource.com/23171 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/mgc.go | 2 +- src/runtime/mgcmark.go | 2 +- src/runtime/proc.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index ae8338ac10bc03..3d4df104cbae0b 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1704,7 +1704,7 @@ func gcSweep(mode gcMode) { lock(&sweep.lock) if sweep.parked { sweep.parked = false - ready(sweep.g, 0) + ready(sweep.g, 0, true) } unlock(&sweep.lock) mProf_GC() diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 5d947fb59e6d50..dfddd8c6f6730b 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -601,7 +601,7 @@ func gcFlushBgCredit(scanWork int64) { gp.gcAssistBytes = 0 xgp := gp gp = gp.schedlink.ptr() - ready(xgp, 0) + ready(xgp, 0, true) } else { // Partially satisfy this assist. gp.gcAssistBytes += scanBytes diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 15dcb95c9c6960..3a37fa947beeaa 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -273,7 +273,7 @@ func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) { func goready(gp *g, traceskip int) { systemstack(func() { - ready(gp, traceskip) + ready(gp, traceskip, true) }) } @@ -533,7 +533,7 @@ func mcommoninit(mp *m) { } // Mark gp ready to run. -func ready(gp *g, traceskip int) { +func ready(gp *g, traceskip int, next bool) { if trace.enabled { traceGoUnpark(gp, traceskip) } @@ -550,7 +550,7 @@ func ready(gp *g, traceskip int) { // status is Gwaiting or Gscanwaiting, make Grunnable and put on runq casgstatus(gp, _Gwaiting, _Grunnable) - runqput(_g_.m.p.ptr(), gp, true) + runqput(_g_.m.p.ptr(), gp, next) if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 { // TODO: fast atomic wakep() } @@ -1835,7 +1835,7 @@ top: } if fingwait && fingwake { if gp := wakefing(); gp != nil { - ready(gp, 0) + ready(gp, 0, true) } } From 44497ebacb6336e4cc9ce2934840bdd68e8c46c0 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 17 May 2016 18:46:03 -0400 Subject: [PATCH 168/267] runtime: fix goroutine priority elevation Currently it's possible for user code to exploit the high scheduler priority of the GC worker in conjunction with the runnext optimization to elevate a user goroutine to high priority so it will always run even if there are other runnable goroutines. For example, if a goroutine is in a tight allocation loop, the following can happen: 1. Goroutine 1 allocates, triggering a GC. 2. G 1 attempts an assist, but fails and blocks. 3. The scheduler runs the GC worker, since it is high priority. Note that this also starts a new scheduler quantum. 4. The GC worker does enough work to satisfy the assist. 5. The GC worker readies G 1, putting it in runnext. 6. GC finishes and the scheduler runs G 1 from runnext, giving it the rest of the GC worker's quantum. 7. Go to 1. Even if there are other goroutines on the run queue, they never get a chance to run in the above sequence. This requires a confluence of circumstances that make it unlikely, though not impossible, that it would happen in "real" code. In the test added by this commit, we force this confluence by setting GOMAXPROCS to 1 and GOGC to 1 so it's easy for the test to repeated trigger GC and wake from a blocked assist. We fix this by making GC always put user goroutines at the end of the run queue, instead of in runnext. This makes it so user code can't piggy-back on the GC's high priority to make a user goroutine act like it has high priority. The only other situation where GC wakes user goroutines is waking all blocked assists at the end, but this uses the global run queue and hence doesn't have this problem. Fixes #15706. Change-Id: I1589dee4b7b7d0c9c8575ed3472226084dfce8bc Reviewed-on: https://go-review.googlesource.com/23172 Reviewed-by: Rick Hudson --- src/runtime/mgcmark.go | 8 ++++++- src/runtime/proc_test.go | 8 +++++++ src/runtime/testdata/testprog/gc.go | 35 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index dfddd8c6f6730b..cbdf2b8375149d 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -601,7 +601,13 @@ func gcFlushBgCredit(scanWork int64) { gp.gcAssistBytes = 0 xgp := gp gp = gp.schedlink.ptr() - ready(xgp, 0, true) + // It's important that we *not* put xgp in + // runnext. Otherwise, it's possible for user + // code to exploit the GC worker's high + // scheduler priority to get itself always run + // before other goroutines and always in the + // fresh quantum started by GC. + ready(xgp, 0, false) } else { // Partially satisfy this assist. gp.gcAssistBytes += scanBytes diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go index 89941210719954..22e4dca771c6c0 100644 --- a/src/runtime/proc_test.go +++ b/src/runtime/proc_test.go @@ -344,6 +344,14 @@ func TestGCFairness(t *testing.T) { } } +func TestGCFairness2(t *testing.T) { + output := runTestProg(t, "testprog", "GCFairness2") + want := "OK\n" + if output != want { + t.Fatalf("want %s, got %s\n", want, output) + } +} + func TestNumGoroutine(t *testing.T) { output := runTestProg(t, "testprog", "NumGoroutine") want := "1\n" diff --git a/src/runtime/testdata/testprog/gc.go b/src/runtime/testdata/testprog/gc.go index 0676e9a4eccd2a..a0c1f82b56bd62 100644 --- a/src/runtime/testdata/testprog/gc.go +++ b/src/runtime/testdata/testprog/gc.go @@ -8,11 +8,14 @@ import ( "fmt" "os" "runtime" + "runtime/debug" + "sync/atomic" "time" ) func init() { register("GCFairness", GCFairness) + register("GCFairness2", GCFairness2) register("GCSys", GCSys) } @@ -72,3 +75,35 @@ func GCFairness() { time.Sleep(10 * time.Millisecond) fmt.Println("OK") } + +func GCFairness2() { + // Make sure user code can't exploit the GC's high priority + // scheduling to make scheduling of user code unfair. See + // issue #15706. + runtime.GOMAXPROCS(1) + debug.SetGCPercent(1) + var count [3]int64 + var sink [3]interface{} + for i := range count { + go func(i int) { + for { + sink[i] = make([]byte, 1024) + atomic.AddInt64(&count[i], 1) + } + }(i) + } + // Note: If the unfairness is really bad, it may not even get + // past the sleep. + // + // If the scheduling rules change, this may not be enough time + // to let all goroutines run, but for now we cycle through + // them rapidly. + time.Sleep(30 * time.Millisecond) + for i := range count { + if atomic.LoadInt64(&count[i]) == 0 { + fmt.Printf("goroutine %d did not run\n", i) + return + } + } + fmt.Println("OK") +} From 3b50adbc4f1a9d775f0434166ad71220e8a4b8ce Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 19 May 2016 17:43:04 +0000 Subject: [PATCH 169/267] build: unset GOBIN during build Fixes #14340 Change-Id: I43e1624fafc972fb868708c3857fc8acf1bfbbd7 Reviewed-on: https://go-review.googlesource.com/23255 Run-TryBot: Brad Fitzpatrick Reviewed-by: Rob Pike --- src/make.bash | 3 +++ src/make.bat | 1 + src/make.rc | 2 +- src/run.bash | 1 + src/run.bat | 2 ++ src/run.rc | 1 + 6 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/make.bash b/src/make.bash index 82c903eadbb8b6..1a1412a00cf57e 100755 --- a/src/make.bash +++ b/src/make.bash @@ -50,6 +50,9 @@ # GO_DISTFLAGS: extra flags to provide to "dist bootstrap". set -e + +unset GOBIN # Issue 14340 + if [ ! -f run.bash ]; then echo 'make.bash must be run from $GOROOT/src' 1>&2 exit 1 diff --git a/src/make.bat b/src/make.bat index a64777ee917d31..bf25b95ca5097d 100644 --- a/src/make.bat +++ b/src/make.bat @@ -68,6 +68,7 @@ setlocal set GOROOT=%GOROOT_BOOTSTRAP% set GOOS= set GOARCH= +set GOBIN= "%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist endlocal if errorlevel 1 goto fail diff --git a/src/make.rc b/src/make.rc index 60162045ede4b0..243f83cc0f0223 100755 --- a/src/make.rc +++ b/src/make.rc @@ -80,7 +80,7 @@ if(~ $sysname vx32) if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){ echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^. - GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \ + GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH GOBIN= \ $GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd echo } diff --git a/src/run.bash b/src/run.bash index 3acf46a9961a2d..293b775efa5e77 100755 --- a/src/run.bash +++ b/src/run.bash @@ -11,6 +11,7 @@ export GOROOT # the api test requires GOROOT to be set. unset CDPATH # in case user has it set unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens # to be under $GOPATH, then some tests below will fail +unset GOBIN # Issue 14340 export GOHOSTOS export CC diff --git a/src/run.bat b/src/run.bat index 01a66bc574876a..6e42922a86e594 100644 --- a/src/run.bat +++ b/src/run.bat @@ -15,6 +15,8 @@ set GOBUILDFAIL=0 :: we disallow local import for non-local packages, if %GOROOT% happens :: to be under %GOPATH%, then some tests below will fail set GOPATH= +:: Issue 14340: ignore GOBIN during all.bat. +set GOBIN= rem TODO avoid rebuild if possible diff --git a/src/run.rc b/src/run.rc index d314808f3f28a7..88d77912e31efc 100755 --- a/src/run.rc +++ b/src/run.rc @@ -9,5 +9,6 @@ eval `{go env} GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens # to be under $GOPATH, then some tests below will fail +GOBIN = () # Issue 14340 exec go tool dist test -rebuild $* From 0b80659832ec72532ee1210cdb51422ee6012c66 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 19 May 2016 18:05:10 +0000 Subject: [PATCH 170/267] net/http/httptest: restore historic ResponseRecorder.HeaderMap behavior In Go versions 1 up to and including Go 1.6, ResponseRecorder.HeaderMap was both the map that handlers got access to, and was the map tests checked their results against. That did not mimic the behavior of the real HTTP server (Issue #8857), so HeaderMap was changed to be a snapshot at the first write in https://golang.org/cl/20047. But that broke cases where the Handler never did a write (#15560), so revert the behavior. Instead, introduce the ResponseWriter.Result method, returning an *http.Response. It subsumes ResponseWriter.Trailers which was added for Go 1.7 in CL 20047. Result().Header now contains the correct answer, and HeaderMap is unchanged in behavior from previous Go releases, so we don't break people's tests. People wanting the correct behavior can use ResponseWriter.Result. Fixes #15560 Updates #8857 Change-Id: I7ea9b56a6b843103784553d67f67847b5315b3d2 Reviewed-on: https://go-review.googlesource.com/23257 Reviewed-by: Damien Neil Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/httptest/recorder.go | 101 +++++++++++++++++-------- src/net/http/httptest/recorder_test.go | 62 +++++++++++++-- 2 files changed, 124 insertions(+), 39 deletions(-) diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go index b1f49541d576e5..0ad26a3d418005 100644 --- a/src/net/http/httptest/recorder.go +++ b/src/net/http/httptest/recorder.go @@ -6,6 +6,7 @@ package httptest import ( "bytes" + "io/ioutil" "net/http" ) @@ -17,9 +18,8 @@ type ResponseRecorder struct { Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to Flushed bool - stagingMap http.Header // map that handlers manipulate to set headers - trailerMap http.Header // lazily filled when Trailers() is called - + result *http.Response // cache of Result's return value + snapHeader http.Header // snapshot of HeaderMap at first Write wroteHeader bool } @@ -38,10 +38,10 @@ const DefaultRemoteAddr = "1.2.3.4" // Header returns the response headers. func (rw *ResponseRecorder) Header() http.Header { - m := rw.stagingMap + m := rw.HeaderMap if m == nil { m = make(http.Header) - rw.stagingMap = m + rw.HeaderMap = m } return m } @@ -104,11 +104,17 @@ func (rw *ResponseRecorder) WriteHeader(code int) { if rw.HeaderMap == nil { rw.HeaderMap = make(http.Header) } - for k, vv := range rw.stagingMap { + rw.snapHeader = cloneHeader(rw.HeaderMap) +} + +func cloneHeader(h http.Header) http.Header { + h2 := make(http.Header, len(h)) + for k, vv := range h { vv2 := make([]string, len(vv)) copy(vv2, vv) - rw.HeaderMap[k] = vv2 + h2[k] = vv2 } + return h2 } // Flush sets rw.Flushed to true. @@ -119,32 +125,61 @@ func (rw *ResponseRecorder) Flush() { rw.Flushed = true } -// Trailers returns any trailers set by the handler. It must be called -// after the handler finished running. -func (rw *ResponseRecorder) Trailers() http.Header { - if rw.trailerMap != nil { - return rw.trailerMap - } - trailers, ok := rw.HeaderMap["Trailer"] - if !ok { - rw.trailerMap = make(http.Header) - return rw.trailerMap - } - rw.trailerMap = make(http.Header, len(trailers)) - for _, k := range trailers { - switch k { - case "Transfer-Encoding", "Content-Length", "Trailer": - // Ignore since forbidden by RFC 2616 14.40. - continue - } - k = http.CanonicalHeaderKey(k) - vv, ok := rw.stagingMap[k] - if !ok { - continue +// Result returns the response generated by the handler. +// +// The returned Response will have at least its StatusCode, +// Header, Body, and optionally Trailer populated. +// More fields may be populated in the future, so callers should +// not DeepEqual the result in tests. +// +// The Response.Header is a snapshot of the headers at the time of the +// first write call, or at the time of this call, if the handler never +// did a write. +// +// Result must only be called after the handler has finished running. +func (rw *ResponseRecorder) Result() *http.Response { + if rw.result != nil { + return rw.result + } + if rw.snapHeader == nil { + rw.snapHeader = cloneHeader(rw.HeaderMap) + } + res := &http.Response{ + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + StatusCode: rw.Code, + Header: rw.snapHeader, + } + rw.result = res + if res.StatusCode == 0 { + res.StatusCode = 200 + } + res.Status = http.StatusText(res.StatusCode) + if rw.Body != nil { + res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes())) + } + + if trailers, ok := rw.snapHeader["Trailer"]; ok { + res.Trailer = make(http.Header, len(trailers)) + for _, k := range trailers { + // TODO: use http2.ValidTrailerHeader, but we can't + // get at it easily because it's bundled into net/http + // unexported. This is good enough for now: + switch k { + case "Transfer-Encoding", "Content-Length", "Trailer": + // Ignore since forbidden by RFC 2616 14.40. + continue + } + k = http.CanonicalHeaderKey(k) + vv, ok := rw.HeaderMap[k] + if !ok { + continue + } + vv2 := make([]string, len(vv)) + copy(vv2, vv) + res.Trailer[k] = vv2 } - vv2 := make([]string, len(vv)) - copy(vv2, vv) - rw.trailerMap[k] = vv2 } - return rw.trailerMap + return res } diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go index 19a37b6c54d2d6..d4e7137913e492 100644 --- a/src/net/http/httptest/recorder_test.go +++ b/src/net/http/httptest/recorder_test.go @@ -23,6 +23,14 @@ func TestRecorder(t *testing.T) { return nil } } + hasResultStatus := func(wantCode int) checkFunc { + return func(rec *ResponseRecorder) error { + if rec.Result().StatusCode != wantCode { + return fmt.Errorf("Result().StatusCode = %d; want %d", rec.Result().StatusCode, wantCode) + } + return nil + } + } hasContents := func(want string) checkFunc { return func(rec *ResponseRecorder) error { if rec.Body.String() != want { @@ -39,10 +47,18 @@ func TestRecorder(t *testing.T) { return nil } } - hasHeader := func(key, want string) checkFunc { + hasOldHeader := func(key, want string) checkFunc { return func(rec *ResponseRecorder) error { if got := rec.HeaderMap.Get(key); got != want { - return fmt.Errorf("header %s = %q; want %q", key, got, want) + return fmt.Errorf("HeaderMap header %s = %q; want %q", key, got, want) + } + return nil + } + } + hasHeader := func(key, want string) checkFunc { + return func(rec *ResponseRecorder) error { + if got := rec.Result().Header.Get(key); got != want { + return fmt.Errorf("final header %s = %q; want %q", key, got, want) } return nil } @@ -50,9 +66,9 @@ func TestRecorder(t *testing.T) { hasNotHeaders := func(keys ...string) checkFunc { return func(rec *ResponseRecorder) error { for _, k := range keys { - _, ok := rec.HeaderMap[http.CanonicalHeaderKey(k)] + v, ok := rec.Result().Header[http.CanonicalHeaderKey(k)] if ok { - return fmt.Errorf("unexpected header %s", k) + return fmt.Errorf("unexpected header %s with value %q", k, v) } } return nil @@ -60,7 +76,7 @@ func TestRecorder(t *testing.T) { } hasTrailer := func(key, want string) checkFunc { return func(rec *ResponseRecorder) error { - if got := rec.Trailers().Get(key); got != want { + if got := rec.Result().Trailer.Get(key); got != want { return fmt.Errorf("trailer %s = %q; want %q", key, got, want) } return nil @@ -68,7 +84,7 @@ func TestRecorder(t *testing.T) { } hasNotTrailers := func(keys ...string) checkFunc { return func(rec *ResponseRecorder) error { - trailers := rec.Trailers() + trailers := rec.Result().Trailer for _, k := range keys { _, ok := trailers[http.CanonicalHeaderKey(k)] if ok { @@ -194,6 +210,40 @@ func TestRecorder(t *testing.T) { hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"), ), }, + { + "Header set without any write", // Issue 15560 + func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Foo", "1") + + // Simulate somebody using + // new(ResponseRecorder) instead of + // using the constructor which sets + // this to 200 + w.(*ResponseRecorder).Code = 0 + }, + check( + hasOldHeader("X-Foo", "1"), + hasStatus(0), + hasHeader("X-Foo", "1"), + hasResultStatus(200), + ), + }, + { + "HeaderMap vs FinalHeaders", // more for Issue 15560 + func(w http.ResponseWriter, r *http.Request) { + h := w.Header() + h.Set("X-Foo", "1") + w.Write([]byte("hi")) + h.Set("X-Foo", "2") + h.Set("X-Bar", "2") + }, + check( + hasOldHeader("X-Foo", "2"), + hasOldHeader("X-Bar", "2"), + hasHeader("X-Foo", "1"), + hasNotHeaders("X-Bar"), + ), + }, } r, _ := http.NewRequest("GET", "http://foo.com/", nil) for _, tt := range tests { From dc4427f3727804ded270bc6a7a8066ccb3c151d0 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 19 May 2016 18:08:43 +0000 Subject: [PATCH 171/267] context: make DeadlineExceeded have a Timeout method Fixes #14238 Change-Id: I1538bfb5cfa63e36a89df1f6eb9f5a0dcafb6ce5 Reviewed-on: https://go-review.googlesource.com/23256 Reviewed-by: Dave Cheney Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/context/context.go | 8 +++++++- src/context/context_test.go | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/context/context.go b/src/context/context.go index 9ff19503b203ad..169db74f57ffe0 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -144,7 +144,13 @@ var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. -var DeadlineExceeded = errors.New("context deadline exceeded") +var DeadlineExceeded error = deadlineExceededError{} + +type deadlineExceededError struct{} + +func (deadlineExceededError) Error() string { return "context deadline exceeded" } + +func (deadlineExceededError) Timeout() bool { return true } // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. diff --git a/src/context/context_test.go b/src/context/context_test.go index 99456b188d2a65..90e78e57ecc42e 100644 --- a/src/context/context_test.go +++ b/src/context/context_test.go @@ -594,3 +594,15 @@ func recoveredValue(fn func()) (v interface{}) { fn() return } + +func TestDeadlineExceededSupportsTimeout(t *testing.T) { + i, ok := DeadlineExceeded.(interface { + Timeout() bool + }) + if !ok { + t.Fatal("DeadlineExceeded does not support Timeout interface") + } + if !i.Timeout() { + t.Fatal("wrong value for timeout") + } +} From 448246adff7feb868d66cfde82b36fcfd0e66b75 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 18 May 2016 17:43:15 -0700 Subject: [PATCH 172/267] cmd/compile: don't exit early because of hidden error messages Non-syntax errors are always counted to determine if to exit early, but then deduplication eliminates them. This can lead to situations which report "too many errors" and only one error is shown. De-duplicate non-syntax errors early, at least the ones that appear consecutively, and only count the ones actually being shown. This doesn't work perfectly as they may not appear in sequence, but it's cheap and good enough. Fixes #14136. Change-Id: I7b11ebb2e1e082f0d604b88e544fe5ba967af1d7 Reviewed-on: https://go-review.googlesource.com/23259 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/subr.go | 51 ++++++++++++++++------------- test/fixedbugs/issue14136.go | 19 +++++++++++ 2 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 test/fixedbugs/issue14136.go diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 3ce8bd16d2d5eb..6cfc610650a393 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -87,46 +87,53 @@ func linestr(line int32) string { return Ctxt.Line(int(line)) } -func yyerrorl(line int32, format string, args ...interface{}) { - adderr(line, format, args...) - - hcrash() - nerrors++ - if nsavederrors+nerrors >= 10 && Debug['e'] == 0 { - Flusherrors() - fmt.Printf("%v: too many errors\n", linestr(line)) - errorexit() - } +// lasterror keeps track of the most recently issued error. +// It is used to avoid multiple error messages on the same +// line. +var lasterror struct { + syntax int32 // line of last syntax error + other int32 // line of last non-syntax error + msg string // error message of last non-syntax error } -var yyerror_lastsyntax int32 - -func Yyerror(format string, args ...interface{}) { +func yyerrorl(line int32, format string, args ...interface{}) { msg := fmt.Sprintf(format, args...) + if strings.HasPrefix(msg, "syntax error") { nsyntaxerrors++ - - // only one syntax error per line - if yyerror_lastsyntax == lineno { + // only one syntax error per line, no matter what error + if lasterror.syntax == line { return } - yyerror_lastsyntax = lineno - - yyerrorl(lineno, "%s", msg) - return + lasterror.syntax = line + } else { + // only one of multiple equal non-syntax errors per line + // (Flusherrors shows only one of them, so we filter them + // here as best as we can (they may not appear in order) + // so that we don't count them here and exit early, and + // then have nothing to show for.) + if lasterror.other == line && lasterror.msg == msg { + return + } + lasterror.other = line + lasterror.msg = msg } - adderr(lineno, "%s", msg) + adderr(line, "%s", msg) hcrash() nerrors++ if nsavederrors+nerrors >= 10 && Debug['e'] == 0 { Flusherrors() - fmt.Printf("%v: too many errors\n", linestr(lineno)) + fmt.Printf("%v: too many errors\n", linestr(line)) errorexit() } } +func Yyerror(format string, args ...interface{}) { + yyerrorl(lineno, format, args...) +} + func Warn(fmt_ string, args ...interface{}) { adderr(lineno, fmt_, args...) diff --git a/test/fixedbugs/issue14136.go b/test/fixedbugs/issue14136.go new file mode 100644 index 00000000000000..928a60bf6b5ab8 --- /dev/null +++ b/test/fixedbugs/issue14136.go @@ -0,0 +1,19 @@ +// 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. + +// Test that > 10 non-syntax errors on the same line +// don't lead to early exit. Specifically, here test +// that we see the initialization error for variable +// s. + +package main + +type T struct{} + +func main() { + t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown T field" + var s string = 1 // ERROR "cannot use 1" +} From 8527b8ef9b00c72b1a8e30e5917c7bdd3c0e79ef Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Wed, 18 May 2016 18:47:24 -0700 Subject: [PATCH 173/267] syscall: add Unshare flags to SysProcAttr on Linux This patch adds Unshare flags to SysProcAttr for Linux systems. Fixes #1954 Change-Id: Id819c3f92b1474e5a06dd8d55f89d74a43eb770c Reviewed-on: https://go-review.googlesource.com/23233 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/syscall/exec_linux.go | 9 +++++++++ src/syscall/exec_linux_test.go | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index e49bad75b284ff..5a6b2049970901 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -32,6 +32,7 @@ type SysProcAttr struct { Pgid int // Child's process group ID if Setpgid. Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) + Unshare uintptr // Flags for unshare calls (Linux only) UidMappings []SysProcIDMap // User ID mappings for user namespaces. GidMappings []SysProcIDMap // Group ID mappings for user namespaces. // GidMappingsEnableSetgroups enabling setgroups syscall. @@ -194,6 +195,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Unshare + if sys.Unshare != 0 { + _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshare, 0, 0) + if err1 != 0 { + goto childerror + } + } + // User and groups if cred := sys.Credential; cred != nil { ngroups := uintptr(len(cred.Groups)) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index eb32cfd4b1e46c..ec5be107e049f8 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -125,3 +125,39 @@ func TestEmptyCredGroupsDisableSetgroups(t *testing.T) { t.Fatal(err) } } + +func TestUnshare(t *testing.T) { + // Make sure we are running as root so we have permissions to use unshare + // and create a network namespace. + if os.Getuid() != 0 { + t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace") + } + + // When running under the Go continuous build, skip tests for + // now when under Kubernetes. (where things are root but not quite) + // Both of these are our own environment variables. + // See Issue 12815. + if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" { + t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") + } + + cmd := exec.Command("ip", "a") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Unshare: syscall.CLONE_NEWNET, + } + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Cmd failed with err %v, output: %s", err, out) + } + + // Check there is only the local network interface + sout := strings.TrimSpace(string(out)) + if !strings.Contains(sout, "lo") { + t.Fatalf("Expected lo network interface to exist, got %s", sout) + } + + lines := strings.Split(sout, "\n") + if len(lines) != 2 { + t.Fatalf("Expected 2 lines of output, got %d", len(lines)) + } +} From 9cd2c700deccc6dfcc8f264857e406c53bf07859 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 19 May 2016 06:15:18 +0900 Subject: [PATCH 174/267] net: deflake TestDialTimeoutMaxDuration Fixes #15745. Change-Id: I6f9a1dcf0b1d97cb443900c7d8da09ead83d4b6a Reviewed-on: https://go-review.googlesource.com/23243 Run-TryBot: Mikio Hara Reviewed-by: Ian Lance Taylor --- src/net/timeout_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go index 86010927b321ef..7991a579fd1b34 100644 --- a/src/net/timeout_test.go +++ b/src/net/timeout_test.go @@ -124,7 +124,7 @@ func TestDialTimeoutMaxDuration(t *testing.T) { for i, tt := range dialTimeoutMaxDurationTests { ch := make(chan error) - max := time.NewTimer(100 * time.Millisecond) + max := time.NewTimer(250 * time.Millisecond) defer max.Stop() go func() { d := Dialer{Timeout: tt.timeout} From 16f846a9cbe747b13498761f1dd1a298478ec43e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 19 May 2016 17:35:23 +0000 Subject: [PATCH 175/267] net/http: update bundled http2 Updates x/net/http2 to git rev 202ff482 for https://golang.org/cl/23235 (Expect: 100-continue support for HTTP/2) Fixes a flaky test too, and changes the automatic HTTP/2 behavior to no longer special-case the DefaultTransport, because ExpectContinueTimeout is no longer unsupported by the HTTP/2 transport. Fixes #13851 Fixes #15744 Change-Id: I3522aace14179a1ca070fd7063368a831167a0f7 Reviewed-on: https://go-review.googlesource.com/23254 Reviewed-by: Andrew Gerrand --- src/net/http/h2_bundle.go | 168 +++++++++++++++++++++++++++------ src/net/http/transport.go | 15 +-- src/net/http/transport_test.go | 17 ++-- 3 files changed, 153 insertions(+), 47 deletions(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 6f7fd382ea088b..633bdeadb705f0 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1975,6 +1975,10 @@ func http2summarizeFrame(f http2Frame) string { return buf.String() } +func http2transportExpectContinueTimeout(t1 *Transport) time.Duration { + return t1.ExpectContinueTimeout +} + type http2contextContext interface { context.Context } @@ -2010,8 +2014,8 @@ func http2traceGotConn(req *Request, cc *http2ClientConn) { ci := httptrace.GotConnInfo{Conn: cc.tconn} cc.mu.Lock() ci.Reused = cc.nextStreamID > 1 - ci.WasIdle = len(cc.streams) == 0 - if ci.WasIdle { + ci.WasIdle = len(cc.streams) == 0 && ci.Reused + if ci.WasIdle && !cc.lastActive.IsZero() { ci.IdleTime = time.Now().Sub(cc.lastActive) } cc.mu.Unlock() @@ -2025,6 +2029,18 @@ func http2traceWroteHeaders(trace *http2clientTrace) { } } +func http2traceGot100Continue(trace *http2clientTrace) { + if trace != nil && trace.Got100Continue != nil { + trace.Got100Continue() + } +} + +func http2traceWait100Continue(trace *http2clientTrace) { + if trace != nil && trace.Wait100Continue != nil { + trace.Wait100Continue() + } +} + func http2traceWroteRequest(trace *http2clientTrace, err error) { if trace != nil && trace.WroteRequest != nil { trace.WroteRequest(httptrace.WroteRequestInfo{Err: err}) @@ -4906,6 +4922,7 @@ type http2clientStream struct { resc chan http2resAndError bufPipe http2pipe // buffered pipe with the flow-controlled response payload requestedGzip bool + on100 func() // optional code to run if get a 100 continue response flow http2flow // guarded by cc.mu inflow http2flow // guarded by cc.mu @@ -5114,6 +5131,13 @@ func (t *http2Transport) disableKeepAlives() bool { return t.t1 != nil && t.t1.DisableKeepAlives } +func (t *http2Transport) expectContinueTimeout() time.Duration { + if t.t1 == nil { + return 0 + } + return http2transportExpectContinueTimeout(t.t1) +} + func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { if http2VerboseLogs { t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr()) @@ -5311,6 +5335,30 @@ func http2checkConnHeaders(req *Request) error { return nil } +func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) { + body = req.Body + if body == nil { + return nil, 0 + } + if req.ContentLength != 0 { + return req.Body, req.ContentLength + } + + // We have a body but a zero content length. Test to see if + // it's actually zero or just unset. + var buf [1]byte + n, rerr := io.ReadFull(body, buf[:]) + if rerr != nil && rerr != io.EOF { + return http2errorReader{rerr}, -1 + } + if n == 1 { + + return io.MultiReader(bytes.NewReader(buf[:]), body), -1 + } + + return nil, 0 +} + func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { if err := http2checkConnHeaders(req); err != nil { return nil, err @@ -5322,24 +5370,8 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } hasTrailers := trailers != "" - var body io.Reader = req.Body - contentLen := req.ContentLength - if req.Body != nil && contentLen == 0 { - // Test to see if it's actually zero or just unset. - var buf [1]byte - n, rerr := io.ReadFull(body, buf[:]) - if rerr != nil && rerr != io.EOF { - contentLen = -1 - body = http2errorReader{rerr} - } else if n == 1 { - - contentLen = -1 - body = io.MultiReader(bytes.NewReader(buf[:]), body) - } else { - - body = nil - } - } + body, contentLen := http2bodyAndLength(req) + hasBody := body != nil cc.mu.Lock() cc.lastActive = time.Now() @@ -5367,8 +5399,9 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cs := cc.newStream() cs.req = req cs.trace = http2requestTrace(req) - hasBody := body != nil cs.requestedGzip = requestedGzip + bodyWriter := cc.t.getBodyWriterState(cs, body) + cs.on100 = bodyWriter.on100 cc.wmu.Lock() endStream := !hasBody && !hasTrailers @@ -5380,6 +5413,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { if werr != nil { if hasBody { req.Body.Close() + bodyWriter.cancel() } cc.forgetStreamID(cs.ID) @@ -5388,12 +5422,8 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } var respHeaderTimer <-chan time.Time - var bodyCopyErrc chan error // result of body copy if hasBody { - bodyCopyErrc = make(chan error, 1) - go func() { - bodyCopyErrc <- cs.writeRequestBody(body, req.Body) - }() + bodyWriter.scheduleBodyWrite() } else { http2traceWroteRequest(cs.trace, nil) if d := cc.responseHeaderTimeout(); d != 0 { @@ -5413,6 +5443,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { res := re.res if re.err != nil || res.StatusCode > 299 { + bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWrite) } if re.err != nil { @@ -5427,6 +5458,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { + bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } return nil, http2errTimeout @@ -5435,6 +5467,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { + bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } return nil, ctx.Err() @@ -5443,14 +5476,14 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { + bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } return nil, http2errRequestCanceled case <-cs.peerReset: return nil, cs.resetErr - case err := <-bodyCopyErrc: - http2traceWroteRequest(cs.trace, err) + case err := <-bodyWriter.resc: if err != nil { return nil, err } @@ -5508,6 +5541,7 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos defer cc.putFrameScratchBuffer(buf) defer func() { + http2traceWroteRequest(cs.trace, err) cerr := bodyCloser.Close() if err == nil { @@ -5934,7 +5968,10 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http } if statusCode == 100 { - + http2traceGot100Continue(cs.trace) + if cs.on100 != nil { + cs.on100() + } cs.pastHeaders = false return nil, nil } @@ -6344,6 +6381,79 @@ type http2errorReader struct{ err error } func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err } +// bodyWriterState encapsulates various state around the Transport's writing +// of the request body, particularly regarding doing delayed writes of the body +// when the request contains "Expect: 100-continue". +type http2bodyWriterState struct { + cs *http2clientStream + timer *time.Timer // if non-nil, we're doing a delayed write + fnonce *sync.Once // to call fn with + fn func() // the code to run in the goroutine, writing the body + resc chan error // result of fn's execution + delay time.Duration // how long we should delay a delayed write for +} + +func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reader) (s http2bodyWriterState) { + s.cs = cs + if body == nil { + return + } + resc := make(chan error, 1) + s.resc = resc + s.fn = func() { + resc <- cs.writeRequestBody(body, cs.req.Body) + } + s.delay = t.expectContinueTimeout() + if s.delay == 0 || + !httplex.HeaderValuesContainsToken( + cs.req.Header["Expect"], + "100-continue") { + return + } + s.fnonce = new(sync.Once) + + // Arm the timer with a very large duration, which we'll + // intentionally lower later. It has to be large now because + // we need a handle to it before writing the headers, but the + // s.delay value is defined to not start until after the + // request headers were written. + const hugeDuration = 365 * 24 * time.Hour + s.timer = time.AfterFunc(hugeDuration, func() { + s.fnonce.Do(s.fn) + }) + return +} + +func (s http2bodyWriterState) cancel() { + if s.timer != nil { + s.timer.Stop() + } +} + +func (s http2bodyWriterState) on100() { + if s.timer == nil { + + return + } + s.timer.Stop() + go func() { s.fnonce.Do(s.fn) }() +} + +// scheduleBodyWrite starts writing the body, either immediately (in +// the common case) or after the delay timeout. It should not be +// called until after the headers have been written. +func (s http2bodyWriterState) scheduleBodyWrite() { + if s.timer == nil { + + go s.fn() + return + } + http2traceWait100Continue(s.cs.trace) + if s.timer.Stop() { + s.timer.Reset(s.delay) + } +} + // writeFramer is implemented by any type that is used to write frames. type http2writeFramer interface { writeFrame(http2writeContext) error diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 777501f5bd42bd..37fa7a0783369c 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -205,15 +205,6 @@ func (t *Transport) onceSetNextProtoDefaults() { // by modifying their tls.Config. Issue 14275. return } - if t.ExpectContinueTimeout != 0 && t != DefaultTransport { - // ExpectContinueTimeout is unsupported in http2, so - // if they explicitly asked for it (as opposed to just - // using the DefaultTransport, which sets it), then - // disable http2 for now. - // - // Issue 13851. (and changed in Issue 14391) - return - } t2, err := http2configureTransport(t) if err != nil { log.Printf("Error enabling Transport HTTP/2 support: %v", err) @@ -854,7 +845,7 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC select { case v := <-dialc: // Our dial finished. - if trace != nil && trace.GotConn != nil && v.pc != nil { + if trace != nil && trace.GotConn != nil && v.pc != nil && v.pc.alt == nil { trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn}) } return v.pc, v.err @@ -1243,7 +1234,9 @@ func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnIn t.Reused = pc.reused t.Conn = pc.conn t.WasIdle = true - t.IdleTime = time.Since(idleAt) + if !idleAt.IsZero() { + t.IdleTime = time.Since(idleAt) + } return } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index ab05c31cb55501..b80c151a244514 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2983,7 +2983,7 @@ func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) { func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) { testTransportAutoHTTP(t, &Transport{ ExpectContinueTimeout: 1 * time.Second, - }, false) + }, true) } func TestTransportAutomaticHTTP2_Dial(t *testing.T) { @@ -3225,9 +3225,8 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { io.WriteString(w, resBody) })) defer cst.close() - if !h2 { - cst.tr.ExpectContinueTimeout = 1 * time.Second - } + + cst.tr.ExpectContinueTimeout = 1 * time.Second var mu sync.Mutex var buf bytes.Buffer @@ -3283,10 +3282,12 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { if err != nil { t.Fatal(err) } + logf("got roundtrip.response") slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatal(err) } + logf("consumed body") if string(slurp) != resBody || res.StatusCode != 200 { t.Fatalf("Got %q, %v; want %q, 200 OK", slurp, res.Status, resBody) } @@ -3305,6 +3306,9 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { t.Errorf("expected substring %q in output.", sub) } } + if strings.Count(got, "got conn: {") != 1 { + t.Errorf("expected exactly 1 \"got conn\" event.") + } wantSub("Getting conn for dns-is-faked.golang:" + port) wantSub("DNS start: {Host:dns-is-faked.golang}") wantSub("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err: Coalesced:false}") @@ -3314,10 +3318,9 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { wantSub("first response byte") if !h2 { wantSub("PutIdleConn = ") - // TODO: implement these next two for Issue 13851 - wantSub("Wait100Continue") - wantSub("Got100Continue") } + wantSub("Wait100Continue") + wantSub("Got100Continue") wantSub("WroteRequest: {Err:}") if strings.Contains(got, " to udp ") { t.Errorf("should not see UDP (DNS) connections") From 1ded9fdcff8722ae961fb9da015faac874b7690e Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Thu, 19 May 2016 22:26:01 -0700 Subject: [PATCH 176/267] syscall: fix unshare test on mips Change-Id: Iedce3770a92112802f3a45c7b95ee145ab5b187e Reviewed-on: https://go-review.googlesource.com/23282 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/syscall/exec_linux_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index ec5be107e049f8..099756328c9cb4 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -141,7 +141,7 @@ func TestUnshare(t *testing.T) { t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") } - cmd := exec.Command("ip", "a") + cmd := exec.Command("cat", "/proc/net/dev") cmd.SysProcAttr = &syscall.SysProcAttr{ Unshare: syscall.CLONE_NEWNET, } @@ -152,12 +152,12 @@ func TestUnshare(t *testing.T) { // Check there is only the local network interface sout := strings.TrimSpace(string(out)) - if !strings.Contains(sout, "lo") { + if !strings.Contains(sout, "lo:") { t.Fatalf("Expected lo network interface to exist, got %s", sout) } lines := strings.Split(sout, "\n") - if len(lines) != 2 { - t.Fatalf("Expected 2 lines of output, got %d", len(lines)) + if len(lines) != 3 { + t.Fatalf("Expected 3 lines of output, got %d", len(lines)) } } From b3bf2e7803174b77838a357ee05b1351ece6a29d Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 03:01:27 +0000 Subject: [PATCH 177/267] net/http: update bundled http2 Updates x/net/http2 to git rev 8a52c78 for golang.org/cl/23258 (http2: fix Transport.CloseIdleConnections when http1+http2 are wired together) Fixes #14607 Change-Id: I038badc69e230715b8ce4e398eb5e6ede73af918 Reviewed-on: https://go-review.googlesource.com/23280 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/clientserver_test.go | 29 ++++++++++++++++++++++++++++ src/net/http/export_test.go | 30 ++++++++++++++++++----------- src/net/http/h2_bundle.go | 32 +++++++++++++++++++++---------- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index b1b7d137d93c52..e12ea0c8c45b40 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -1196,6 +1196,35 @@ func TestH12_AutoGzipWithDumpResponse(t *testing.T) { }.run(t) } +// Issue 14607 +func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) } +func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) } +func testCloseIdleConnections(t *testing.T, h2 bool) { + defer afterTest(t) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("X-Addr", r.RemoteAddr) + })) + defer cst.close() + get := func() string { + res, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + v := res.Header.Get("X-Addr") + if v == "" { + t.Fatal("didn't get X-Addr") + } + return v + } + a1 := get() + cst.tr.CloseIdleConnections() + a2 := get() + if a1 == a2 { + t.Errorf("didn't close connection") + } +} + type noteCloseConn struct { net.Conn closeFunc func() diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index 3ebc51b19e62e9..9c5ba0809ad0ab 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -15,17 +15,16 @@ import ( ) var ( - DefaultUserAgent = defaultUserAgent - NewLoggingConn = newLoggingConn - ExportAppendTime = appendTime - ExportRefererForURL = refererForURL - ExportServerNewConn = (*Server).newConn - ExportCloseWriteAndWait = (*conn).closeWriteAndWait - ExportErrRequestCanceled = errRequestCanceled - ExportErrRequestCanceledConn = errRequestCanceledConn - ExportServeFile = serveFile - ExportHttp2ConfigureTransport = http2ConfigureTransport - ExportHttp2ConfigureServer = http2ConfigureServer + DefaultUserAgent = defaultUserAgent + NewLoggingConn = newLoggingConn + ExportAppendTime = appendTime + ExportRefererForURL = refererForURL + ExportServerNewConn = (*Server).newConn + ExportCloseWriteAndWait = (*conn).closeWriteAndWait + ExportErrRequestCanceled = errRequestCanceled + ExportErrRequestCanceledConn = errRequestCanceledConn + ExportServeFile = serveFile + ExportHttp2ConfigureServer = http2ConfigureServer ) func init() { @@ -152,3 +151,12 @@ func hookSetter(dst *func()) func(func()) { *dst = fn } } + +func ExportHttp2ConfigureTransport(t *Transport) error { + t2, err := http2configureTransport(t) + if err != nil { + return err + } + t.h2transport = t2 + return nil +} diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 633bdeadb705f0..55111523e587f5 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -50,6 +50,18 @@ type http2ClientConnPool interface { MarkDead(*http2ClientConn) } +// clientConnPoolIdleCloser is the interface implemented by ClientConnPool +// implementations which can close their idle connections. +type http2clientConnPoolIdleCloser interface { + http2ClientConnPool + closeIdleConnections() +} + +var ( + _ http2clientConnPoolIdleCloser = (*http2clientConnPool)(nil) + _ http2clientConnPoolIdleCloser = http2noDialClientConnPool{} +) + // TODO: use singleflight for dialing and addConnCalls? type http2clientConnPool struct { t *http2Transport @@ -250,6 +262,15 @@ func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) [ return out } +// noDialClientConnPool is an implementation of http2.ClientConnPool +// which never dials. We let the HTTP/1.1 client dial and use its TLS +// connection instead. +type http2noDialClientConnPool struct{ *http2clientConnPool } + +func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) { + return p.getClientConn(req, addr, http2noDialOnMiss) +} + func http2configureTransport(t1 *Transport) (*http2Transport, error) { connPool := new(http2clientConnPool) t2 := &http2Transport{ @@ -302,15 +323,6 @@ func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) { return nil } -// noDialClientConnPool is an implementation of http2.ClientConnPool -// which never dials. We let the HTTP/1.1 client dial and use its TLS -// connection instead. -type http2noDialClientConnPool struct{ *http2clientConnPool } - -func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) { - return p.getClientConn(req, addr, http2noDialOnMiss) -} - // noDialH2RoundTripper is a RoundTripper which only tries to complete the request // if there's already has a cached connection to the host. type http2noDialH2RoundTripper struct{ t *http2Transport } @@ -5054,7 +5066,7 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res // connected from previous requests but are now sitting idle. // It does not interrupt any connections currently in use. func (t *http2Transport) CloseIdleConnections() { - if cp, ok := t.connPool().(*http2clientConnPool); ok { + if cp, ok := t.connPool().(http2clientConnPoolIdleCloser); ok { cp.closeIdleConnections() } } From be1b93065356e71362ca8469fc53c9ab102c4be5 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 19 May 2016 13:31:58 -0400 Subject: [PATCH 178/267] reflect: hide unexported methods that do not satisfy interfaces Fixes #15673 Change-Id: Ib36d8db3299a93d92665dbde012d52c2c5332ac0 Reviewed-on: https://go-review.googlesource.com/23253 Reviewed-by: Russ Cox Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/reflect/all_test.go | 19 ++++---- src/reflect/type.go | 100 +++++++++++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 9799fee3573557..f09ffeb56615c5 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -2388,13 +2388,13 @@ type outer struct { inner } -func (*inner) m() {} -func (*outer) m() {} +func (*inner) M() {} +func (*outer) M() {} func TestNestedMethods(t *testing.T) { typ := TypeOf((*outer)(nil)) - if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() { - t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m) + if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() { + t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M) for i := 0; i < typ.NumMethod(); i++ { m := typ.Method(i) t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer()) @@ -2416,18 +2416,15 @@ var unexpi unexpI = new(unexp) func TestUnexportedMethods(t *testing.T) { typ := TypeOf(unexpi) + if got := typ.NumMethod(); got != 1 { + t.Error("NumMethod=%d, want 1 satisfied method", got) + } if typ.Method(0).Type == nil { t.Error("missing type for satisfied method 'f'") } if !typ.Method(0).Func.IsValid() { t.Error("missing func for satisfied method 'f'") } - if typ.Method(1).Type != nil { - t.Error("found type for unsatisfied method 'g'") - } - if typ.Method(1).Func.IsValid() { - t.Error("found func for unsatisfied method 'g'") - } } type InnerInt struct { @@ -5187,7 +5184,7 @@ func useStack(n int) { type Impl struct{} -func (Impl) f() {} +func (Impl) F() {} func TestValueString(t *testing.T) { rv := ValueOf(Impl{}) diff --git a/src/reflect/type.go b/src/reflect/type.go index dd7b797c048230..c9389199d8b963 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -763,16 +763,63 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 } func (t *rtype) common() *rtype { return t } +var methodCache struct { + sync.RWMutex + m map[*rtype][]method +} + +// satisfiedMethods returns methods of t that satisfy an interface. +// This may include unexported methods that satisfy an interface +// defined with unexported methods in the same package as t. +func (t *rtype) satisfiedMethods() []method { + methodCache.RLock() + methods, found := methodCache.m[t] + methodCache.RUnlock() + + if found { + return methods + } + + ut := t.uncommon() + if ut == nil { + return nil + } + allm := ut.methods() + allSatisfied := true + for _, m := range allm { + if m.mtyp == 0 { + allSatisfied = false + break + } + } + if allSatisfied { + methods = allm + } else { + methods = make([]method, 0, len(allm)) + for _, m := range allm { + if m.mtyp != 0 { + methods = append(methods, m) + } + } + methods = methods[:len(methods):len(methods)] + } + + methodCache.Lock() + if methodCache.m == nil { + methodCache.m = make(map[*rtype][]method) + } + methodCache.m[t] = methods + methodCache.Unlock() + + return methods +} + func (t *rtype) NumMethod() int { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.NumMethod() } - ut := t.uncommon() - if ut == nil { - return 0 - } - return int(ut.mcount) + return len(t.satisfiedMethods()) } func (t *rtype) Method(i int) (m Method) { @@ -780,40 +827,39 @@ func (t *rtype) Method(i int) (m Method) { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.Method(i) } - ut := t.uncommon() - - if ut == nil || i < 0 || i >= int(ut.mcount) { + methods := t.satisfiedMethods() + if i < 0 || i >= len(methods) { panic("reflect: Method index out of range") } - p := ut.methods()[i] + p := methods[i] pname := t.nameOff(p.name) m.Name = pname.name() fl := flag(Func) if !pname.isExported() { m.PkgPath = pname.pkgPath() if m.PkgPath == "" { + ut := t.uncommon() m.PkgPath = t.nameOff(ut.pkgPath).name() } fl |= flagStickyRO } - if p.mtyp != 0 { - mtyp := t.typeOff(p.mtyp) - ft := (*funcType)(unsafe.Pointer(mtyp)) - in := make([]Type, 0, 1+len(ft.in())) - in = append(in, t) - for _, arg := range ft.in() { - in = append(in, arg) - } - out := make([]Type, 0, len(ft.out())) - for _, ret := range ft.out() { - out = append(out, ret) - } - mt := FuncOf(in, out, ft.IsVariadic()) - m.Type = mt - tfn := t.textOff(p.tfn) - fn := unsafe.Pointer(&tfn) - m.Func = Value{mt.(*rtype), fn, fl} + mtyp := t.typeOff(p.mtyp) + ft := (*funcType)(unsafe.Pointer(mtyp)) + in := make([]Type, 0, 1+len(ft.in())) + in = append(in, t) + for _, arg := range ft.in() { + in = append(in, arg) } + out := make([]Type, 0, len(ft.out())) + for _, ret := range ft.out() { + out = append(out, ret) + } + mt := FuncOf(in, out, ft.IsVariadic()) + m.Type = mt + tfn := t.textOff(p.tfn) + fn := unsafe.Pointer(&tfn) + m.Func = Value{mt.(*rtype), fn, fl} + m.Index = i return m } @@ -831,7 +877,7 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) { for i := 0; i < int(ut.mcount); i++ { p := utmethods[i] pname := t.nameOff(p.name) - if pname.name() == name { + if pname.isExported() && pname.name() == name { return t.Method(i), true } } From 85e39f838722a1521e09288cddfe378843d662fb Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 16:30:49 +0000 Subject: [PATCH 179/267] net/http: also clone DynamicRecordSizingDisabled in cloneTLSConfig Updates #15771 Change-Id: I5dad96bdca19d680dd00cbd17b72a03e43eb557e Reviewed-on: https://go-review.googlesource.com/23283 Reviewed-by: Tom Bergan Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick --- src/net/http/transport.go | 77 ++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 37fa7a0783369c..57ebbd57e12c44 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -2005,25 +2005,27 @@ func cloneTLSConfig(cfg *tls.Config) *tls.Config { return &tls.Config{} } return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - SessionTicketsDisabled: cfg.SessionTicketsDisabled, - SessionTicketKey: cfg.SessionTicketKey, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + SessionTicketsDisabled: cfg.SessionTicketsDisabled, + SessionTicketKey: cfg.SessionTicketKey, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, + Renegotiation: cfg.Renegotiation, } } @@ -2036,24 +2038,25 @@ func cloneTLSClientConfig(cfg *tls.Config) *tls.Config { return &tls.Config{} } return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - Renegotiation: cfg.Renegotiation, + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, + Renegotiation: cfg.Renegotiation, } } From 4cad610401edc11fe921205438a7b3ab4faa3982 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 20:42:21 +0000 Subject: [PATCH 180/267] os/exec: remove Cmd.RunContext and Cmd.WaitContext, add CommandContext Fixes #15775 Change-Id: I0a6c2ca09d3850c3538494711f7a9801b9500411 Reviewed-on: https://go-review.googlesource.com/23300 Run-TryBot: Brad Fitzpatrick Reviewed-by: Brad Fitzpatrick --- src/os/exec/exec.go | 38 +++++++++++++++++++------------------- src/os/exec/exec_test.go | 18 +++++++++++++----- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go index 5121b9b2ccca48..10300ce234a751 100644 --- a/src/os/exec/exec.go +++ b/src/os/exec/exec.go @@ -103,8 +103,9 @@ type Cmd struct { // available after a call to Wait or Run. ProcessState *os.ProcessState - lookPathErr error // LookPath error, if any. - finished bool // when Wait was called + ctx context.Context // nil means none + lookPathErr error // LookPath error, if any. + finished bool // when Wait was called childFiles []*os.File closeAfterStart []io.Closer closeAfterWait []io.Closer @@ -139,6 +140,20 @@ func Command(name string, arg ...string) *Cmd { return cmd } +// CommandContext is like Command but includes a context. +// +// The provided context is used to kill the process (by calling +// os.Process.Kill) if the context becomes done before the command +// completes on its own. +func CommandContext(ctx context.Context, name string, arg ...string) *Cmd { + if ctx == nil { + panic("nil Context") + } + cmd := Command(name, arg...) + cmd.ctx = ctx + return cmd +} + // interfaceEqual protects against panics from doing equality tests on // two interfaces with non-comparable underlying types. func interfaceEqual(a, b interface{}) bool { @@ -263,15 +278,6 @@ func (c *Cmd) Run() error { return c.Wait() } -// RunContext is like Run, but kills the process (by calling os.Process.Kill) -// if ctx is done before the process ends on its own. -func (c *Cmd) RunContext(ctx context.Context) error { - if err := c.Start(); err != nil { - return err - } - return c.WaitContext(ctx) -} - // lookExtensions finds windows executable by its dir and path. // It uses LookPath to try appropriate extensions. // lookExtensions does not search PATH, instead it converts `prog` into `.\prog`. @@ -396,12 +402,6 @@ func (e *ExitError) Error() string { // // Wait releases any resources associated with the Cmd. func (c *Cmd) Wait() error { - return c.WaitContext(nil) -} - -// WaitContext is like Wait, but kills the process (by calling os.Process.Kill) -// if ctx is done before the process ends on its own. -func (c *Cmd) WaitContext(ctx context.Context) error { if c.Process == nil { return errors.New("exec: not started") } @@ -411,11 +411,11 @@ func (c *Cmd) WaitContext(ctx context.Context) error { c.finished = true var waitDone chan struct{} - if ctx != nil { + if c.ctx != nil { waitDone = make(chan struct{}) go func() { select { - case <-ctx.Done(): + case <-c.ctx.Done(): c.Process.Kill() case <-waitDone: } diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 0cff3bb9264e7f..41f9dfe1c63614 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -29,16 +29,24 @@ import ( "time" ) -func helperCommand(t *testing.T, s ...string) *exec.Cmd { +func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) { testenv.MustHaveExec(t) cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) - cmd := exec.Command(os.Args[0], cs...) + if ctx != nil { + cmd = exec.CommandContext(ctx, os.Args[0], cs...) + } else { + cmd = exec.Command(os.Args[0], cs...) + } cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} return cmd } +func helperCommand(t *testing.T, s ...string) *exec.Cmd { + return helperCommandContext(t, nil, s...) +} + func TestEcho(t *testing.T) { bs, err := helperCommand(t, "echo", "foo bar", "baz").Output() if err != nil { @@ -834,7 +842,8 @@ func TestOutputStderrCapture(t *testing.T) { } func TestContext(t *testing.T) { - c := helperCommand(t, "pipetest") + ctx, cancel := context.WithCancel(context.Background()) + c := helperCommandContext(t, ctx, "pipetest") stdin, err := c.StdinPipe() if err != nil { t.Fatal(err) @@ -843,7 +852,6 @@ func TestContext(t *testing.T) { if err != nil { t.Fatal(err) } - ctx, cancel := context.WithCancel(context.Background()) if err := c.Start(); err != nil { t.Fatal(err) } @@ -858,7 +866,7 @@ func TestContext(t *testing.T) { } waitErr := make(chan error, 1) go func() { - waitErr <- c.WaitContext(ctx) + waitErr <- c.Wait() }() cancel() select { From db5af0d7115781be12f510322ee01556fb1e6d16 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 20:58:44 +0000 Subject: [PATCH 181/267] net/http: update bundled http2 Updates x/net/http2 to git rev 4d07e8a49 for CL 23287: http2: let handlers close Request.Body without killing streams https://golang.org/cl/23287 Fixes #15425 Change-Id: I20b6e37cd09aa1d5a040c122ca0daf14b8916559 Reviewed-on: https://go-review.googlesource.com/23301 Run-TryBot: Brad Fitzpatrick Reviewed-by: Brad Fitzpatrick --- src/net/http/h2_bundle.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 55111523e587f5..563e2c0c9b7d6c 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -4351,7 +4351,7 @@ type http2requestBody struct { func (b *http2requestBody) Close() error { if b.pipe != nil { - b.pipe.CloseWithError(http2errClosedBody) + b.pipe.BreakWithError(http2errClosedBody) } b.closed = true return nil @@ -4976,12 +4976,14 @@ func (cs *http2clientStream) awaitRequestCancel(req *Request) { } } -// checkReset reports any error sent in a RST_STREAM frame by the -// server. -func (cs *http2clientStream) checkReset() error { +// checkResetOrDone reports any error sent in a RST_STREAM frame by the +// server, or errStreamClosed if the stream is complete. +func (cs *http2clientStream) checkResetOrDone() error { select { case <-cs.peerReset: return cs.resetErr + case <-cs.done: + return http2errStreamClosed default: return nil } @@ -5641,7 +5643,7 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er if cs.stopReqBody != nil { return 0, cs.stopReqBody } - if err := cs.checkReset(); err != nil { + if err := cs.checkResetOrDone(); err != nil { return 0, err } if a := cs.flow.available(); a > 0 { @@ -5810,6 +5812,7 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr cc.lastActive = time.Now() delete(cc.streams, id) close(cs.done) + cc.cond.Broadcast() } return cs } From cc0d8c86e3437c1eec697809bdc9b2bcc8e0ed92 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 18:13:49 +0000 Subject: [PATCH 182/267] net/http: deflake TestTransportEventTrace_h2 Fixes #15765 Change-Id: Id0a89d90ef9d3fffa9af0affca8c10a26fe6b7bc Reviewed-on: https://go-review.googlesource.com/23284 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/http/transport_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index b80c151a244514..1c1a1d0397234b 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3218,10 +3218,18 @@ func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace( func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { defer afterTest(t) const resBody = "some body" + gotWroteReqEvent := make(chan struct{}) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { if _, err := ioutil.ReadAll(r.Body); err != nil { t.Error(err) } + if !noHooks { + select { + case <-gotWroteReqEvent: + case <-time.After(5 * time.Second): + t.Error("timeout waiting for WroteRequest event") + } + } io.WriteString(w, resBody) })) defer cst.close() @@ -3269,7 +3277,10 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { }, Wait100Continue: func() { logf("Wait100Continue") }, Got100Continue: func() { logf("Got100Continue") }, - WroteRequest: func(e httptrace.WroteRequestInfo) { logf("WroteRequest: %+v", e) }, + WroteRequest: func(e httptrace.WroteRequestInfo) { + close(gotWroteReqEvent) + logf("WroteRequest: %+v", e) + }, } if noHooks { // zero out all func pointers, trying to get some path to crash From 054a721dcac9b30610af0898b3ed8bf3ffa9f8b1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 20 May 2016 11:19:19 -0700 Subject: [PATCH 183/267] cmd/compile: read safemode bit from package header Ignore respective bit in export data, but leave the info to minimize format changes for 1.7. Scheduled to remove by 1.8. For #15772. Change-Id: Ifb3beea655367308a4e2d5dc8cb625915f904287 Reviewed-on: https://go-review.googlesource.com/23285 Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/bimport.go | 4 +++- src/cmd/compile/internal/gc/main.go | 15 +++++++++++++++ src/cmd/compile/internal/gc/parser.go | 6 +----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index 51847538961eec..e1885981e04699 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -103,7 +103,9 @@ func Import(in *bufio.Reader) { // --- compiler-specific export data --- // read compiler-specific flags - importpkg.Safe = p.bool() + + // read but ignore safemode bit (see issue #15772) + p.bool() // formerly: importpkg.Safe = p.bool() // phase 2 objcount = 0 diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 713ff13d8547d8..8ad3300dbed3e2 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -784,6 +784,21 @@ func importfile(f *Val, indent []byte) { } } + // process header lines + for { + p, err = imp.ReadString('\n') + if err != nil { + log.Fatalf("reading input: %v", err) + } + if p == "\n" { + break // header ends with blank line + } + if strings.HasPrefix(p, "safe") { + importpkg.Safe = true + break // ok to ignore rest + } + } + // assume files move (get installed) // so don't record the full path. linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 55f352590bb351..7ffd42f83cba51 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -398,11 +398,8 @@ func (p *parser) import_package() { p.import_error() } - importsafe := false + // read but skip "safe" bit (see issue #15772) if p.tok == LNAME { - if p.sym_.Name == "safe" { - importsafe = true - } p.next() } p.want(';') @@ -413,7 +410,6 @@ func (p *parser) import_package() { } else if importpkg.Name != name { Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path) } - importpkg.Safe = importsafe typecheckok = true defercheckwidth() From 7ab698b0221fd4a5b2842fb50a34ba8a5f49c6d5 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 22:43:14 +0000 Subject: [PATCH 184/267] time: document that After uses memory until duration times out Fixes #15698 Change-Id: I616fc06dcf04092bafdaf56fb1afba2a998a6d83 Reviewed-on: https://go-review.googlesource.com/23304 Reviewed-by: Ian Lance Taylor --- src/time/sleep.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/time/sleep.go b/src/time/sleep.go index c348366604e6db..7661f7e54fc130 100644 --- a/src/time/sleep.go +++ b/src/time/sleep.go @@ -106,6 +106,9 @@ func sendTime(c interface{}, seq uintptr) { // After waits for the duration to elapse and then sends the current time // on the returned channel. // It is equivalent to NewTimer(d).C. +// The underlying Timer is not recovered by the garbage collector +// until the timer fires. If efficiency is a concern, use NewTimer +// instead and call Timer.Stop if the timer is no longer needed. func After(d Duration) <-chan Time { return NewTimer(d).C } From da5ac69bd4dce05443220c73c9eadb606b9777f8 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 21:52:59 +0000 Subject: [PATCH 185/267] A+C: automated updates Add Aiden Scandella (individual CLA) Add Alessandro Arzilli (individual CLA) Add Augusto Roman (individual CLA) Add Brady Catherman (individual CLA) Add Brady Sullivan (individual CLA) Add Caio Marcelo de Oliveira Filho (corporate CLA for Intel Corporation) Add Catalin Nicutar (corporate CLA for Google Inc.) Add Cherry Zhang (corporate CLA for Google Inc.) Add Chris Zou (corporate CLA for IBM) Add Christopher Nelson (individual CLA) Add Conrad Irwin (individual CLA) Add Cuihtlauac ALVARADO (corporate CLA for Orange) Add Daniel Speichert (individual CLA) Add Datong Sun (individual CLA) Add Denys Honsiorovskyi (individual CLA) Add Derek Shockey (individual CLA) Add Dmitriy Dudkin (individual CLA) Add Dustin Herbis (individual CLA) Add Frits van Bommel (individual CLA) Add Harshavardhana (individual CLA) Add Hitoshi Mitake (individual CLA) Add James Bardin (individual CLA) Add James Chacon (corporate CLA for Google Inc.) Add Jamil Djadala (individual CLA) Add Jess Frazelle (individual CLA) Add Joe Sylve (individual CLA) Add Johan Sageryd (individual CLA) Add John Jeffery (individual CLA) Add Julia Hansbrough (corporate CLA for Google Inc.) Add Jure Ham (corporate CLA for Zemanta d.o.o.) Add Kamal Aboul-Hosn (corporate CLA for Google Inc.) Add Kevin Burke (individual CLA) Add Kevin Kirsche (individual CLA) Add Kevin Vu (individual CLA) Add Lee Hinman (individual CLA) Add Luan Santos (individual CLA) Add Marc-Antoine Ruel (corporate CLA for Google Inc.) Add Matt Robenolt (individual CLA) Add Michael McConville (individual CLA) Add Michael Munday (corporate CLA for IBM) Add Michael Pratt (corporate CLA for Google Inc.) Add Michel Lespinasse (corporate CLA for Google Inc.) Add Mike Danese (corporate CLA for Google Inc.) Add Mikhail Gusarov (individual CLA) Add Monty Taylor (individual CLA) Add Morten Siebuhr (individual CLA) Add Muhammed Uluyol (individual CLA) Add Niels Widger (individual CLA) Add Niko Dziemba (individual CLA) Add Olivier Poitrey (individual CLA) Add Paul Wankadia (corporate CLA for Google Inc.) Add Philip Hofer (individual CLA) Add Prashant Varanasi (individual CLA) Add Rhys Hiltner (corporate CLA for Amazon.com, Inc) Add Richard Miller (individual CLA) Add Scott Bell (individual CLA) Add Shahar Kohanim (individual CLA) Add Shinji Tanaka (individual CLA) Add Suharsh Sivakumar (corporate CLA for Google Inc.) Add Tal Shprecher (individual CLA) Add Tilman Dilo (individual CLA) Add Tim Ebringer (individual CLA) Add Tom Bergan (corporate CLA for Google Inc.) Add Vishvananda Ishaya (individual CLA) Add Wedson Almeida Filho (corporate CLA for Google Inc.) Add Zhongwei Yao (corporate CLA for ARM Ltd.) Updates #12042 Change-Id: Ia118adc2eb38e5ffc8448de2d9dd3ca792ee7227 Reviewed-on: https://go-review.googlesource.com/23303 Reviewed-by: Ian Lance Taylor --- AUTHORS | 50 +++++++++++++++++++++++++++++++++++++++ CONTRIBUTORS | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/AUTHORS b/AUTHORS index 39098fca93d80a..f4e01265167772 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,6 +20,7 @@ Adrian O'Grady Adrien Bustany Aécio Júnior Ahmed Waheed Moanes +Aiden Scandella Ainar Garipov Akshat Kumar Alan Shreve @@ -28,6 +29,7 @@ Alberto Bertogli Alberto Donizetti Alberto García Hierro Aleksandar Dezelin +Alessandro Arzilli Alex A Skinner Alex Brainman Alex Jin @@ -50,6 +52,7 @@ Alexey Borzenkov Alexey Palazhchenko Aliaksandr Valialkin Alif Rachmawadi +Amazon.com, Inc Amir Mohammad Saied Amrut Joshi Andrei Korzhevskii @@ -85,6 +88,7 @@ Anthony Starks Apisak Darakananda Aram Hăvărneanu Areski Belaid +ARM Ltd. Arnaud Ysmal Arne Hormann Arnout Engelen @@ -92,6 +96,7 @@ Aron Nopanen Artyom Pervukhin Arvindh Rajesh Tamilmani Ato Araki +Augusto Roman Aulus Egnatius Varialus awaw fumin Aymerick Jéhanne @@ -107,6 +112,8 @@ Bjorn Tipling Blake Gentry Blake Mizerany Bobby Powers +Brady Catherman +Brady Sullivan Brendan Daniel Tracey Brett Cannon Brian Dellisanti @@ -140,6 +147,7 @@ Christoffer Buchholz Christoph Hack Christopher Cahoon Christopher Guiney +Christopher Nelson Christopher Nielsen Christopher Redden Christopher Wedgwood @@ -147,6 +155,7 @@ CL Sung Clement Skau CloudFlare Inc. Colin Kennedy +Conrad Irwin Conrad Meyer CoreOS, Inc. Corey Thomasson @@ -164,8 +173,10 @@ Daniel Lidén Daniel Morsing Daniel Ortiz Pereira da Silva Daniel Skinner +Daniel Speichert Daniel Theophanes Darren Elwood +Datong Sun Dave Cheney David Bürgin <676c7473@gmail.com> David Calavera @@ -182,8 +193,10 @@ Davies Liu Dean Prichard Denis Bernard Denis Brandolini +Denys Honsiorovskyi Derek Buitenhuis Derek Parker +Derek Shockey Develer SRL Devon H. O'Dell Dhiru Kholia @@ -191,6 +204,7 @@ Didier Spezia Dimitri Tcaciuc Dirk Gadsden Dmitri Shuralyov +Dmitriy Dudkin Dmitriy Shelenin Dmitry Chestnykh Dmitry Savintsev @@ -200,6 +214,7 @@ Donald Huang Donovan Hide Dropbox, Inc. Duncan Holm +Dustin Herbis Dustin Sallings Dustin Shields-Cloues Dvir Volk @@ -241,6 +256,7 @@ Francisco Souza Frederick Kelly Mayle III Fredrik Enestad Frithjof Schulze +Frits van Bommel Gabriel Aszalos Gary Burd Gaurish Sharma @@ -266,6 +282,7 @@ Hajime Hoshi Hari haran Hariharan Srinath Harley Laue +Harshavardhana Håvard Haugen Hector Chu Hector Martin Cantero @@ -273,6 +290,7 @@ Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer Hiroshi Ioka +Hitoshi Mitake Hong Ruiqi Hsin-Ho Yeh Hu Keping @@ -290,6 +308,7 @@ Ivan Ukhov Jae Kwon Jakob Borg Jakub Ryszard Czarnowicz +James Bardin James David Chalfant James Fysh James Gray @@ -299,6 +318,7 @@ James Schofield James Sweet James Toy James Whitehead +Jamil Djadala Jan H. Hosang Jan Mercl <0xjnml@gmail.com> Jan Mercl @@ -315,6 +335,7 @@ Jeff Sickel Jeff Wendling Jens Frederich Jeremy Jackins +Jess Frazelle Jihyun Yu Jim McGrath Jimmy Zelinskie @@ -325,12 +346,15 @@ Joakim Sernbrant Joe Harrison Joe Poirier Joe Shaw +Joe Sylve Joe Tsai Joel Stemmer +Johan Sageryd John Asmuth John C Barstow John Graham-Cumming John Howard Palevich +John Jeffery John Jenkins John Potocny John Shahid @@ -368,6 +392,9 @@ Ken Rockot Ken Sedgwick Kenny Grant Kevin Ballard +Kevin Burke +Kevin Kirsche +Kevin Vu Klaus Post Konstantin Shaposhnikov KPCompass, Inc. @@ -379,12 +406,14 @@ Kyle Lemons L Campbell Lai Jiangshan Larz Conwell +Lee Hinman Lee Packham Lewin Bormann Liberty Fund Inc Linaro Limited Lloyd Dewolf Lorenzo Stoakes +Luan Santos Luca Greco Lucien Stuker Lucio De Re @@ -419,6 +448,7 @@ Matt Jibson Matt Joiner Matt Layher Matt Reiferson +Matt Robenolt Matt T. Proud Matt Williams Matthew Brennan @@ -439,6 +469,7 @@ Michael Hoisie Michael Käufl Michael Lewis Michael MacInnis +Michael McConville Michael Pearson Michael Schaller Michael Stapelberg @@ -451,15 +482,19 @@ Mihai Borobocea Mikael Tillenius Mike Andrews Mike Rosset +Mikhail Gusarov Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz Miquel Sabaté Solà Mohit Agarwal +Monty Taylor Moov Corporation Moriyoshi Koizumi +Morten Siebuhr Môshe van der Sterre +Muhammed Uluyol Nan Deng Nathan John Youngman Nathan Otterness @@ -477,7 +512,9 @@ Nick Craig-Wood Nicolas Kaiser Nicolas Owens Nicolas S. Dade +Niels Widger Nigel Kerr +Niko Dziemba Nikolay Turpitko Noah Campbell Norberto Lopes @@ -486,8 +523,10 @@ Oling Cat Oliver Hookins Olivier Antoine Olivier Duperray +Olivier Poitrey Olivier Saingre Oracle +Orange Padraig Kitterick Palm Stone Games Paolo Giarrusso @@ -523,10 +562,12 @@ Péter Szilágyi Peter Waldschmidt Peter Waller Peter Williams +Philip Hofer Philip K. Warren Pierre Roullon Pieter Droogendijk Pietro Gagliardi +Prashant Varanasi Preetam Jinka Quan Yong Zhai Quentin Perez @@ -541,6 +582,7 @@ Rémy Oudompheng Richard Barnes Richard Crowley Richard Eric Gavaletz +Richard Miller Richard Musiol Rick Arnold Risto Jaakko Saarelma @@ -569,6 +611,7 @@ S.Çağlar Onur Salmān Aljammāz Sanjay Menakuru Scott Barron +Scott Bell Scott Ferguson Scott Lawrence Sebastien Binet @@ -577,10 +620,12 @@ Sergei Skorobogatov Sergey 'SnakE' Gromov Sergio Luis O. B. Correia Seth Hoenig +Shahar Kohanim Shane Hansen Shaozhen Ding Shawn Smith Shenghou Ma +Shinji Tanaka Shivakumar GN Silvan Jegen Simon Whitehead @@ -605,6 +650,7 @@ Szabolcs Nagy Tad Glines Taj Khattra Takeshi YAMANASHI <9.nashi@gmail.com> +Tal Shprecher Tamir Duberstein Tarmigan Casebolt Taru Karttunen @@ -615,7 +661,9 @@ Thomas Alan Copeland Thomas Desrosiers Thomas Kappler Thorben Krueger +Tilman Dilo Tim Cooijmans +Tim Ebringer Timo Savola Timo Truyts Tobias Columbus @@ -641,6 +689,7 @@ Vincent Ambo Vincent Batts Vincent Vanackere Vinu Rajashekhar +Vishvananda Ishaya Vladimir Nikishenko Volker Dobler Wei Guangjing @@ -662,6 +711,7 @@ Yoshiyuki Kanno Yusuke Kagiwada Yuusei Kuwana Yuval Pavel Zholkover +Zemanta d.o.o. Ziad Hatahet Zorion Arrizabalaga 申习之 diff --git a/CONTRIBUTORS b/CONTRIBUTORS index bffcb3c7f4562a..6779313e2d6d76 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -44,6 +44,7 @@ Adrian O'Grady Adrien Bustany Aécio Júnior Ahmed Waheed Moanes +Aiden Scandella Ainar Garipov Akshat Kumar Alan Donovan @@ -53,6 +54,7 @@ Alberto Bertogli Alberto Donizetti Alberto García Hierro Aleksandar Dezelin +Alessandro Arzilli Alex A Skinner Alex Brainman Alex Bramley @@ -128,6 +130,7 @@ Artyom Pervukhin Arvindh Rajesh Tamilmani Asim Shankar Ato Araki +Augusto Roman Aulus Egnatius Varialus Austin Clements awaw fumin @@ -153,6 +156,8 @@ Blake Mizerany Bobby Powers Brad Fitzpatrick Brad Garcia +Brady Catherman +Brady Sullivan Brandon Gilmore Brendan Daniel Tracey Brendan O'Dea @@ -166,6 +171,7 @@ Brian Smith Bryan C. Mills Bryan Ford Caine Tighe +Caio Marcelo de Oliveira Filho Caleb Spare Carl Chatfield Carl Jackson @@ -176,6 +182,7 @@ Carlos Cirello Cary Hull Case Nelson Casey Marshall +Catalin Nicutar Catalin Patulea Cedric Staub Cezar Sá Espinola @@ -183,6 +190,7 @@ ChaiShushan Charles L. Dorian Charles Lee Charles Weill +Cherry Zhang Chris Broadfoot Chris Dollin Chris Farmiloe @@ -194,12 +202,14 @@ Chris Kastorff Chris Lennert Chris Manghane Chris McGee +Chris Zou Christian Himpel Christine Hansmann Christoffer Buchholz Christoph Hack Christopher Cahoon Christopher Guiney +Christopher Nelson Christopher Nielsen Christopher Redden Christopher Swenson @@ -209,10 +219,12 @@ Clement Skau Colby Ranger Colin Cross Colin Kennedy +Conrad Irwin Conrad Meyer Corey Thomasson Cosmos Nicolaou Cristian Staretu +Cuihtlauac ALVARADO Damian Gryski Damien Neil Dan Caddigan @@ -230,8 +242,10 @@ Daniel Morsing Daniel Nadasi Daniel Ortiz Pereira da Silva Daniel Skinner +Daniel Speichert Daniel Theophanes Darren Elwood +Datong Sun Dave Borowitz Dave Bort Dave Cheney @@ -262,15 +276,18 @@ Davies Liu Dean Prichard Denis Bernard Denis Brandolini +Denys Honsiorovskyi Derek Buitenhuis Derek Che Derek Parker +Derek Shockey Devon H. O'Dell Dhiru Kholia Didier Spezia Dimitri Tcaciuc Dirk Gadsden Dmitri Shuralyov +Dmitriy Dudkin Dmitriy Shelenin Dmitriy Vyukov Dmitry Chestnykh @@ -282,6 +299,7 @@ Donald Huang Donovan Hide Drew Hintz Duncan Holm +Dustin Herbis Dustin Long Dustin Sallings Dustin Shields-Cloues @@ -332,6 +350,7 @@ Francisco Souza Frederick Kelly Mayle III Fredrik Enestad Frithjof Schulze +Frits van Bommel Fumitoshi Ukai Gaal Yahas Gabriel Aszalos @@ -364,6 +383,7 @@ Han-Wen Nienhuys Hari haran Hariharan Srinath Harley Laue +Harshavardhana Håvard Haugen Hector Chu Hector Martin Cantero @@ -371,6 +391,7 @@ Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer Hiroshi Ioka +Hitoshi Mitake Hong Ruiqi Hossein Sheikh Attar Hsin-Ho Yeh @@ -395,6 +416,8 @@ Jakob Borg Jakub Čajka Jakub Ryszard Czarnowicz James Aguilar +James Bardin +James Chacon James David Chalfant James Fysh James Gray @@ -409,6 +432,7 @@ James Whitehead Jamie Gennis Jamie Turner Jamie Wilkinson +Jamil Djadala Jan H. Hosang Jan Kratochvil Jan Mercl <0xjnml@gmail.com> @@ -431,6 +455,7 @@ Jens Frederich Jeremiah Harmsen Jeremy Jackins Jeremy Schlatter +Jess Frazelle Jihyun Yu Jim Cote Jim McGrath @@ -442,10 +467,12 @@ Joakim Sernbrant Joe Harrison Joe Poirier Joe Shaw +Joe Sylve Joe Tsai Joel Sing Joel Stemmer Johan Euphrosine +Johan Sageryd John Asmuth John Beisley John C Barstow @@ -453,6 +480,7 @@ John DeNero John Dethridge John Graham-Cumming John Howard Palevich +John Jeffery John Jenkins John Newlin John Potocny @@ -482,11 +510,14 @@ Jostein Stuhaug JP Sugarbroad JT Olds Jukka-Pekka Kekkonen +Julia Hansbrough Julian Phillips Julien Schmidt Jungho Ahn +Jure Ham Justin Nuß Kai Backman +Kamal Aboul-Hosn Kamil Kisiel Kang Hu Kato Kazuyoshi @@ -505,8 +536,11 @@ Ken Sedgwick Ken Thompson Kenny Grant Kevin Ballard +Kevin Burke +Kevin Kirsche Kevin Klues Kevin Malachowski +Kevin Vu Kim Shrier Kirklin McDonald Klaus Post @@ -520,11 +554,13 @@ L Campbell Lai Jiangshan Larry Hosken Larz Conwell +Lee Hinman Lee Packham Lewin Bormann Lloyd Dewolf Lorenzo Stoakes Louis Kruger +Luan Santos Luca Greco Lucien Stuker Lucio De Re @@ -540,6 +576,7 @@ Manu Garg Manu S Ajith Manuel Mendez Marc Weistroff +Marc-Antoine Ruel Marcel van Lohuizen Marco Hennings Marga Manterola @@ -570,6 +607,7 @@ Matt Joiner Matt Jones Matt Layher Matt Reiferson +Matt Robenolt Matt T. Proud Matt Williams Matthew Brennan @@ -596,9 +634,12 @@ Michael Lewis Michael MacInnis Michael Marineau Michael Matloob +Michael McConville Michael McGreevy +Michael Munday Michael Pearson Michael Piatek +Michael Pratt Michael Schaller Michael Shields Michael Stapelberg @@ -609,22 +650,28 @@ Michal Bohuslávek Michal Cierniak Michał Derkacz Michalis Kargakis +Michel Lespinasse Miek Gieben Mihai Borobocea Mikael Tillenius Mike Andrews +Mike Danese Mike Rosset Mike Samuel Mike Solomon +Mikhail Gusarov Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz Miquel Sabaté Solà Mohit Agarwal +Monty Taylor Moriyoshi Koizumi +Morten Siebuhr Môshe van der Sterre Mrunal Patel +Muhammed Uluyol Nan Deng Nathan John Youngman Nathan Otterness @@ -643,8 +690,10 @@ Nick Craig-Wood Nicolas Kaiser Nicolas Owens Nicolas S. Dade +Niels Widger Nigel Kerr Nigel Tao +Niko Dziemba Nikolay Turpitko Noah Campbell Nodir Turakulov @@ -654,6 +703,7 @@ Oling Cat Oliver Hookins Olivier Antoine Olivier Duperray +Olivier Poitrey Olivier Saingre Padraig Kitterick Paolo Giarrusso @@ -679,6 +729,7 @@ Paul Rosania Paul Sbarra Paul Smith Paul van Brouwershaven +Paul Wankadia Pavel Paulau Pavel Zinovkin Pawel Knap @@ -702,10 +753,12 @@ Peter Waller Peter Weinberger Peter Williams Phil Pennock +Philip Hofer Philip K. Warren Pierre Roullon Pieter Droogendijk Pietro Gagliardi +Prashant Varanasi Preetam Jinka Quan Yong Zhai Quentin Perez @@ -718,9 +771,11 @@ Raph Levien Raul Silvera Reinaldo de Souza Jr Rémy Oudompheng +Rhys Hiltner Richard Barnes Richard Crowley Richard Eric Gavaletz +Richard Miller Richard Musiol Rick Arnold Rick Hudson @@ -763,6 +818,7 @@ Sameer Ajmani Sanjay Menakuru Sasha Lionheart Scott Barron +Scott Bell Scott Ferguson Scott Lawrence Scott Schwartz @@ -776,12 +832,14 @@ Sergey 'SnakE' Gromov Sergey Arseev Sergio Luis O. B. Correia Seth Hoenig +Shahar Kohanim Shane Hansen Shaozhen Ding Shawn Ledbetter Shawn Smith Shawn Walker-Salas Shenghou Ma +Shinji Tanaka Shivakumar GN Shun Fan Silvan Jegen @@ -804,12 +862,14 @@ Steve Streeting Steven Elliot Harris Steven Hartland Sugu Sougoumarane +Suharsh Sivakumar Sven Almgren Szabolcs Nagy Tad Glines Taj Khattra Takashi Matsuo Takeshi YAMANASHI <9.nashi@gmail.com> +Tal Shprecher Tamir Duberstein Tarmigan Casebolt Taru Karttunen @@ -821,13 +881,16 @@ Thomas Desrosiers Thomas Habets Thomas Kappler Thorben Krueger +Tilman Dilo Tim Cooijmans +Tim Ebringer Tim Hockin Timo Savola Timo Truyts Tobias Columbus Todd Neal Todd Wang +Tom Bergan Tom Heng Tom Linford Tom Szymanski @@ -853,9 +916,11 @@ Vincent Batts Vincent Vanackere Vinu Rajashekhar Vish Subramanian +Vishvananda Ishaya Vlad Krasnov Vladimir Nikishenko Volker Dobler +Wedson Almeida Filho Wei Guangjing Will Chan Will Norris @@ -880,6 +945,7 @@ Yusuke Kagiwada Yuusei Kuwana Yuval Pavel Zholkover Yves Junqueira +Zhongwei Yao Ziad Hatahet Zorion Arrizabalaga 申习之 From 82ec4cd79f117191d12fc14060c4b4b786feca5b Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 13 May 2016 12:13:00 +0900 Subject: [PATCH 186/267] net: don't crash DNS flood test on darwin Also renames the test function to TestDNSFlood. Updates #15659. Change-Id: Ia562004c43bcc19c2fee9440321c27b591f85da5 Reviewed-on: https://go-review.googlesource.com/23077 Reviewed-by: Brad Fitzpatrick --- src/net/lookup_test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 7d18cbdced7f20..e22d1fbf79b42f 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -371,12 +371,23 @@ func TestReverseAddress(t *testing.T) { } } -func TestLookupIPDeadline(t *testing.T) { +func TestDNSFlood(t *testing.T) { if !*testDNSFlood { t.Skip("test disabled; use -dnsflood to enable") } - const N = 5000 + var N = 5000 + if runtime.GOOS == "darwin" { + // On Darwin this test consumes kernel threads much + // than other platforms for some reason. + // When we monitor the number of allocated Ms by + // observing on runtime.newm calls, we can see that it + // easily reaches the per process ceiling + // kern.num_threads when CGO_ENABLED=1 and + // GODEBUG=netdns=go. + N = 500 + } + const timeout = 3 * time.Second ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2) defer cancel() From def50f8e488dcfb12362d4b84feb38de3af5cadc Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 21 May 2016 00:25:48 +0000 Subject: [PATCH 187/267] net/http: update bundled http2 Updates x/net/http2 to git rev 0c607074 for https://golang.org/cl/23311, "http2: prevent Server from sending status 100 header after anything else" New test is in the x/net/http2 package (not bundled to std). Fixes #14030 Change-Id: Ifc6afa4a5fe35977135428f6d0e9f7c164767720 Reviewed-on: https://go-review.googlesource.com/23312 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/h2_bundle.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 563e2c0c9b7d6c..9cedcaa73daab2 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -3111,6 +3111,7 @@ type http2stream struct { sentReset bool // only true once detached from streams map gotReset bool // only true once detacted from streams map gotTrailerHeader bool // HEADER frame for trailers was seen + wroteHeaders bool // whether we wrote headers (not status 100) reqBuf []byte trailer Header // accumulated trailers @@ -3474,7 +3475,21 @@ func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error { // If you're not on the serve goroutine, use writeFrameFromHandler instead. func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) { sc.serveG.check() - sc.writeSched.add(wm) + + var ignoreWrite bool + + switch wm.write.(type) { + case *http2writeResHeaders: + wm.stream.wroteHeaders = true + case http2write100ContinueHeadersFrame: + if wm.stream.wroteHeaders { + ignoreWrite = true + } + } + + if !ignoreWrite { + sc.writeSched.add(wm) + } sc.scheduleFrameWrite() } From 1f8d2768987ea1d7f1bc4d6bbfe59b2a8e98d9b9 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 20 May 2016 23:28:56 +0000 Subject: [PATCH 188/267] A+C: automated update (subrepos) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Abe Haskins (individual CLA) Add Ahmy Yulrizka (individual CLA) Add Akihiro Suda (individual CLA) Add Alex Vaghin (corporate CLA for Google Inc.) Add Arlo Breault (individual CLA) Add Audrey Lim (individual CLA) Add Benjamin Wester (corporate CLA for Square, Inc.) Add Bryan Chan (corporate CLA for IBM) Add Christy Perez (corporate CLA for IBM) Add Colin Edwards (individual CLA) Add David Brophy (individual CLA) Add David Sansome (individual CLA) Add Diwaker Gupta (individual CLA) Add Doug Anderson (corporate CLA for Google Inc.) Add Dustin Carlino (corporate CLA for Google Inc.) Add Ernest Chiang (individual CLA) Add Ethan Burns (corporate CLA for Google Inc.) Add Gary Elliott (corporate CLA for Google Inc.) Add Hallgrimur Gunnarsson (corporate CLA for Google Inc.) Add Hironao OTSUBO (individual CLA) Add Holden Huang (individual CLA) Add Idora Shinatose (individual CLA) Add Irieda Noboru (individual CLA) Add Jeff Craig (corporate CLA for Google Inc.) Add Joe Henke (individual CLA) Add John Schnake (individual CLA) Add Jonathan Amsterdam (corporate CLA for Google Inc.) Add Kenji Kaneda (individual CLA) Add Kenneth Shaw (individual CLA) Add Mark Severson (individual CLA) Add Martin Garton (individual CLA) Add Mathias Leppich (individual CLA) Add Maxwell Krohn (individual CLA) Add Niall Sheridan (individual CLA) Add Nick Patavalis (individual CLA) Add Nick Petroni (individual CLA) Add Omar Jarjur (corporate CLA for Google Inc.) Add Özgür Kesim (individual CLA) Add Peter Gonda (corporate CLA for Google Inc.) Add Pierre Durand (individual CLA) Add Quentin Smith (corporate CLA for Google Inc.) Add Ricardo Padilha (individual CLA) Add Riku Voipio (corporate CLA for Linaro Limited) Add Roland Shoemaker (individual CLA) Add Sam Hug (individual CLA) Add Sam Whited (individual CLA) Add Sami Commerot (corporate CLA for Google Inc.) Add Scott Mansfield (corporate CLA for Netflix, Inc.) Add Sean Harger (corporate CLA for Google Inc.) Add Simon Jefford (individual CLA) Add Sridhar Venkatakrishnan (individual CLA) Add Tim Swast (corporate CLA for Google Inc.) Add Timothy Studd (individual CLA) Add Tipp Moseley (corporate CLA for Google Inc.) Add Toby Burress (corporate CLA for Google Inc.) Add Tzu-Jung Lee (corporate CLA for Currant) Add Vadim Grek (individual CLA) Add Xudong Zhang (individual CLA) Updates #12042 Change-Id: I4119a8829119a2b8a9abbea9f52ceebb04878764 Reviewed-on: https://go-review.googlesource.com/23306 Reviewed-by: Ian Lance Taylor Reviewed-by: Andrew Gerrand --- AUTHORS | 38 ++++++++++++++++++++++++++++++++++ CONTRIBUTORS | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/AUTHORS b/AUTHORS index f4e01265167772..2c2e777992467a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,14 +14,17 @@ A Medium Corporation Aamir Khan Aaron France Aaron Torres +Abe Haskins Abhinav Gupta Adrian Nos Adrian O'Grady Adrien Bustany Aécio Júnior Ahmed Waheed Moanes +Ahmy Yulrizka Aiden Scandella Ainar Garipov +Akihiro Suda Akshat Kumar Alan Shreve Albert Strasheim @@ -88,6 +91,7 @@ Anthony Starks Apisak Darakananda Aram Hăvărneanu Areski Belaid +Arlo Breault ARM Ltd. Arnaud Ysmal Arne Hormann @@ -96,6 +100,7 @@ Aron Nopanen Artyom Pervukhin Arvindh Rajesh Tamilmani Ato Araki +Audrey Lim Augusto Roman Aulus Egnatius Varialus awaw fumin @@ -154,12 +159,14 @@ Christopher Wedgwood CL Sung Clement Skau CloudFlare Inc. +Colin Edwards Colin Kennedy Conrad Irwin Conrad Meyer CoreOS, Inc. Corey Thomasson Cristian Staretu +Currant Damian Gryski Dan Caddigan Dan Callahan @@ -178,6 +185,7 @@ Daniel Theophanes Darren Elwood Datong Sun Dave Cheney +David Brophy David Bürgin <676c7473@gmail.com> David Calavera David du Colombier <0intro@gmail.com> @@ -187,6 +195,7 @@ David Howden David Jakob Fritz David Leon Gil David R. Jenni +David Sansome David Thomas David Titarenco Davies Liu @@ -203,6 +212,7 @@ Dhiru Kholia Didier Spezia Dimitri Tcaciuc Dirk Gadsden +Diwaker Gupta Dmitri Shuralyov Dmitriy Dudkin Dmitriy Shelenin @@ -235,6 +245,7 @@ Erik Aigner Erik Dubbelboer Erik St. Martin Erik Westrup +Ernest Chiang Esko Luontola Evan Phoenix Evan Shaw @@ -289,20 +300,24 @@ Hector Martin Cantero Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer +Hironao OTSUBO Hiroshi Ioka Hitoshi Mitake +Holden Huang Hong Ruiqi Hsin-Ho Yeh Hu Keping Ian Gudger IBM Icarus Sparry +Idora Shinatose Igneous Systems, Inc. Igor Dolzhikov INADA Naoki Ingo Krabbe Ingo Oeser Intel Corporation +Irieda Noboru Isaac Wagner Ivan Ukhov Jae Kwon @@ -344,6 +359,7 @@ Jingguo Yao Jiong Du Joakim Sernbrant Joe Harrison +Joe Henke Joe Poirier Joe Shaw Joe Sylve @@ -357,6 +373,7 @@ John Howard Palevich John Jeffery John Jenkins John Potocny +John Schnake John Shahid John Tuley Jonathan Boulle @@ -390,6 +407,8 @@ Kelvin Foo Chuan Lyi Ken Friedenbach Ken Rockot Ken Sedgwick +Kenji Kaneda +Kenneth Shaw Kenny Grant Kevin Ballard Kevin Burke @@ -426,6 +445,7 @@ Manuel Mendez Marc Weistroff Marco Hennings Mark Bucciarelli +Mark Severson Mark Theunissen Marko Juhani Silokunnas Marko Tiikkaja @@ -433,12 +453,14 @@ Markover Inc. DBA Poptip Markus Duft Markus Sonderegger Markus Zimmermann +Martin Garton Martin Möhrmann Martin Neubauer Martin Olsson Marvin Stenger Mateusz Czapliński Mathias Beke +Mathias Leppich Mathieu Lonjaret Mats Lidell Matt Aimonetti @@ -456,6 +478,7 @@ Matthew Cottingham Matthew Holt Matthew Horsnell Maxim Khitrov +Maxwell Krohn Meir Fischer Meng Zhuo Meteor Development Group @@ -502,13 +525,17 @@ Nathan P Finch Nathan VanBenschoten Nathan Youngman Neelesh Chandola +Netflix, Inc. Nevins Bartolomeo ngmoco, LLC +Niall Sheridan Nicholas Katsaros Nicholas Presta Nicholas Sullivan Nicholas Waples Nick Craig-Wood +Nick Patavalis +Nick Petroni Nicolas Kaiser Nicolas Owens Nicolas S. Dade @@ -527,6 +554,7 @@ Olivier Poitrey Olivier Saingre Oracle Orange +Özgür Kesim Padraig Kitterick Palm Stone Games Paolo Giarrusso @@ -564,6 +592,7 @@ Peter Waller Peter Williams Philip Hofer Philip K. Warren +Pierre Durand Pierre Roullon Pieter Droogendijk Pietro Gagliardi @@ -579,6 +608,7 @@ Ralph Corderoy Red Hat, Inc. Reinaldo de Souza Jr Rémy Oudompheng +Ricardo Padilha Richard Barnes Richard Crowley Richard Eric Gavaletz @@ -598,6 +628,7 @@ Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné Roger Peppe +Roland Shoemaker Ron Hashimoto Ron Minnich Ross Light @@ -609,6 +640,8 @@ Ryan Seys Ryan Slade S.Çağlar Onur Salmān Aljammāz +Sam Hug +Sam Whited Sanjay Menakuru Scott Barron Scott Bell @@ -628,11 +661,13 @@ Shenghou Ma Shinji Tanaka Shivakumar GN Silvan Jegen +Simon Jefford Simon Whitehead Sokolov Yura Spencer Nelson Spring Mc Square, Inc. +Sridhar Venkatakrishnan StalkR Stan Schwertly Stefan Nilsson @@ -666,6 +701,7 @@ Tim Cooijmans Tim Ebringer Timo Savola Timo Truyts +Timothy Studd Tobias Columbus Todd Neal Tom Heng @@ -684,6 +720,7 @@ Ulf Holm Nielsen Ulrich Kunitz Upthere, Inc. Uriel Mangado +Vadim Grek Vadim Vygonets Vincent Ambo Vincent Batts @@ -698,6 +735,7 @@ William Josephson William Orr Xia Bin Xing Xing +Xudong Zhang Yahoo Inc. Yann Kerhervé Yao Zhang diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6779313e2d6d76..de3c41b16e3910 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -37,6 +37,7 @@ Aaron France Aaron Jacobs Aaron Kemp Aaron Torres +Abe Haskins Abhinav Gupta Adam Langley Adrian Nos @@ -44,8 +45,10 @@ Adrian O'Grady Adrien Bustany Aécio Júnior Ahmed Waheed Moanes +Ahmy Yulrizka Aiden Scandella Ainar Garipov +Akihiro Suda Akshat Kumar Alan Donovan Alan Shreve @@ -62,6 +65,7 @@ Alex Jin Alex Plugaru Alex Schroeder Alex Sergeyev +Alex Vaghin Alexander Demakin Alexander Larsson Alexander Morozov @@ -122,6 +126,7 @@ Apisak Darakananda Aram Hăvărneanu Areski Belaid Arkadi Pyuro +Arlo Breault Arnaud Ysmal Arne Hormann Arnout Engelen @@ -130,6 +135,7 @@ Artyom Pervukhin Arvindh Rajesh Tamilmani Asim Shankar Ato Araki +Audrey Lim Augusto Roman Aulus Egnatius Varialus Austin Clements @@ -143,6 +149,7 @@ Ben Lynn Ben Olive Benjamin Black Benjamin Prosnitz +Benjamin Wester Benny Siegert Benoit Sigoure Berengar Lehr @@ -169,6 +176,7 @@ Brian Ketelsen Brian Slesinsky Brian Smith Bryan C. Mills +Bryan Chan Bryan Ford Caine Tighe Caio Marcelo de Oliveira Filho @@ -214,10 +222,12 @@ Christopher Nielsen Christopher Redden Christopher Swenson Christopher Wedgwood +Christy Perez CL Sung Clement Skau Colby Ranger Colin Cross +Colin Edwards Colin Kennedy Conrad Irwin Conrad Meyer @@ -254,6 +264,7 @@ Dave Grijalva David Anderson David Barnett David Benjamin +David Brophy David Bürgin <676c7473@gmail.com> David Calavera David Chase @@ -269,6 +280,7 @@ David Leon Gil David McLeish David Presotto David R. Jenni +David Sansome David Symonds David Thomas David Titarenco @@ -286,6 +298,7 @@ Dhiru Kholia Didier Spezia Dimitri Tcaciuc Dirk Gadsden +Diwaker Gupta Dmitri Shuralyov Dmitriy Dudkin Dmitriy Shelenin @@ -297,8 +310,10 @@ Dominik Honnef Dominik Vogt Donald Huang Donovan Hide +Doug Anderson Drew Hintz Duncan Holm +Dustin Carlino Dustin Herbis Dustin Long Dustin Sallings @@ -323,7 +338,9 @@ Erik Aigner Erik Dubbelboer Erik St. Martin Erik Westrup +Ernest Chiang Esko Luontola +Ethan Burns Evan Broder Evan Brown Evan Kroske @@ -356,6 +373,7 @@ Gaal Yahas Gabriel Aszalos Garrick Evans Gary Burd +Gary Elliott Gaurish Sharma Gautham Thambidorai Geert-Johan Riemer @@ -379,6 +397,7 @@ Gustavo Franco Gustavo Niemeyer Gwenael Treguier Hajime Hoshi +Hallgrimur Gunnarsson Han-Wen Nienhuys Hari haran Hariharan Srinath @@ -390,8 +409,10 @@ Hector Martin Cantero Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer +Hironao OTSUBO Hiroshi Ioka Hitoshi Mitake +Holden Huang Hong Ruiqi Hossein Sheikh Attar Hsin-Ho Yeh @@ -400,11 +421,13 @@ Hyang-Ah Hana Kim Ian Gudger Ian Lance Taylor Icarus Sparry +Idora Shinatose Igor Dolzhikov Ilya Tocar INADA Naoki Ingo Krabbe Ingo Oeser +Irieda Noboru Isaac Wagner Ivan Krasin Ivan Ukhov @@ -447,6 +470,7 @@ Jason Travis Jay Weisskopf Jean-Marc Eurin Jed Denlea +Jeff Craig Jeff Hodges Jeff R. Allen Jeff Sickel @@ -465,6 +489,7 @@ Jingguo Yao Jiong Du Joakim Sernbrant Joe Harrison +Joe Henke Joe Poirier Joe Shaw Joe Sylve @@ -484,9 +509,11 @@ John Jeffery John Jenkins John Newlin John Potocny +John Schnake John Shahid John Tuley Jonathan Allie +Jonathan Amsterdam Jonathan Boulle Jonathan Feinberg Jonathan Gold @@ -534,6 +561,8 @@ Ken Friedenbach Ken Rockot Ken Sedgwick Ken Thompson +Kenji Kaneda +Kenneth Shaw Kenny Grant Kevin Ballard Kevin Burke @@ -582,6 +611,7 @@ Marco Hennings Marga Manterola Marius Nuennerich Mark Bucciarelli +Mark Severson Mark Theunissen Mark Zavislak Marko Juhani Silokunnas @@ -590,12 +620,14 @@ Marko Tiikkaja Markus Duft Markus Sonderegger Markus Zimmermann +Martin Garton Martin Möhrmann Martin Neubauer Martin Olsson Marvin Stenger Mateusz Czapliński Mathias Beke +Mathias Leppich Mathieu Lonjaret Mats Lidell Matt Aimonetti @@ -618,6 +650,7 @@ Matthew Horsnell Maxim Khitrov Maxim Pimenov Maxim Ushakov +Maxwell Krohn Meir Fischer Meng Zhuo Mhd Sulhan @@ -681,12 +714,15 @@ Nathan Youngman Nathan(yinian) Hu Neelesh Chandola Nevins Bartolomeo +Niall Sheridan Nicholas Katsaros Nicholas Presta Nicholas Sullivan Nicholas Waples Nick Cooper Nick Craig-Wood +Nick Patavalis +Nick Petroni Nicolas Kaiser Nicolas Owens Nicolas S. Dade @@ -705,6 +741,8 @@ Olivier Antoine Olivier Duperray Olivier Poitrey Olivier Saingre +Omar Jarjur +Özgür Kesim Padraig Kitterick Paolo Giarrusso Paolo Martini @@ -740,6 +778,7 @@ Petar Maymounkov Peter Armitage Peter Collingbourne Peter Froehlich +Peter Gonda Peter Kleiweg Peter McKenzie Peter Moody @@ -755,6 +794,7 @@ Peter Williams Phil Pennock Philip Hofer Philip K. Warren +Pierre Durand Pierre Roullon Pieter Droogendijk Pietro Gagliardi @@ -762,6 +802,7 @@ Prashant Varanasi Preetam Jinka Quan Yong Zhai Quentin Perez +Quentin Smith Quoc-Viet Nguyen Rahul Chaudhry Raif S. Naffah @@ -772,6 +813,7 @@ Raul Silvera Reinaldo de Souza Jr Rémy Oudompheng Rhys Hiltner +Ricardo Padilha Richard Barnes Richard Crowley Richard Eric Gavaletz @@ -779,6 +821,7 @@ Richard Miller Richard Musiol Rick Arnold Rick Hudson +Riku Voipio Risto Jaakko Saarelma Rob Earhart Rob Norman @@ -798,6 +841,7 @@ Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné Roger Peppe +Roland Shoemaker Ron Hashimoto Ron Minnich Ross Light @@ -813,18 +857,23 @@ Ryan Seys Ryan Slade S.Çağlar Onur Salmān Aljammāz +Sam Hug Sam Thorogood +Sam Whited Sameer Ajmani +Sami Commerot Sanjay Menakuru Sasha Lionheart Scott Barron Scott Bell Scott Ferguson Scott Lawrence +Scott Mansfield Scott Schwartz Scott Van Woudenberg Sean Burford Sean Dolphin +Sean Harger Sebastien Binet Sébastien Paolacci Sergei Skorobogatov @@ -843,11 +892,13 @@ Shinji Tanaka Shivakumar GN Shun Fan Silvan Jegen +Simon Jefford Simon Whitehead Sokolov Yura Spencer Nelson Spring Mc Srdjan Petrovic +Sridhar Venkatakrishnan StalkR Stan Schwertly Stefan Nilsson @@ -885,9 +936,13 @@ Tilman Dilo Tim Cooijmans Tim Ebringer Tim Hockin +Tim Swast Timo Savola Timo Truyts +Timothy Studd +Tipp Moseley Tobias Columbus +Toby Burress Todd Neal Todd Wang Tom Bergan @@ -904,11 +959,13 @@ Trey Tacon Tudor Golubenco Tyler Bunnell Tyler Treat +Tzu-Jung Lee Ugorji Nwoke Ulf Holm Nielsen Ulrich Kunitz Uriel Mangado Uttam C Pawar +Vadim Grek Vadim Vygonets Vega Garcia Luis Alfonso Vincent Ambo @@ -930,6 +987,7 @@ William Josephson William Orr Xia Bin Xing Xing +Xudong Zhang Yan Zou Yann Kerhervé Yao Zhang From 4b6e560b69f3fe6dfadcf6a43eda8a78b086448c Mon Sep 17 00:00:00 2001 From: djherbis Date: Sat, 21 May 2016 13:25:47 -0700 Subject: [PATCH 189/267] AUTHORS: correcting my last name Herbis -> Herbison Change-Id: I91608b15e00c8eaf732db3a99a890d4ceeb41955 Reviewed-on: https://go-review.googlesource.com/23317 Reviewed-by: Ian Lance Taylor --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 2c2e777992467a..bebe250458d048 100644 --- a/AUTHORS +++ b/AUTHORS @@ -224,7 +224,7 @@ Donald Huang Donovan Hide Dropbox, Inc. Duncan Holm -Dustin Herbis +Dustin Herbison Dustin Sallings Dustin Shields-Cloues Dvir Volk diff --git a/CONTRIBUTORS b/CONTRIBUTORS index de3c41b16e3910..4d0863b3efe76c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -314,7 +314,7 @@ Doug Anderson Drew Hintz Duncan Holm Dustin Carlino -Dustin Herbis +Dustin Herbison Dustin Long Dustin Sallings Dustin Shields-Cloues From 65adb6ab9a91c2f4336e1e48f9e7c325dafa0213 Mon Sep 17 00:00:00 2001 From: Kenny Grant Date: Sat, 21 May 2016 16:57:37 +0100 Subject: [PATCH 190/267] time: run genzabbrs.go with new source data The source xml data has changed, so running genzabbrs.go regenerates a new time zone file in zoneinfo_abbrs_windows.go which adds some zones and adjusts others. Now set export ZONEINFO=$GOROOT/lib/time/zoneinfo.zip to use zoneinfo.zip in go tip. Change-Id: I19f72359cc808094e5dcb420e480a00c6b2205d7 Reviewed-on: https://go-review.googlesource.com/23321 Reviewed-by: Alex Brainman Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot --- src/time/zoneinfo_abbrs_windows.go | 40 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go index 51a1a2f66d87e3..344a891d1a4eb1 100644 --- a/src/time/zoneinfo_abbrs_windows.go +++ b/src/time/zoneinfo_abbrs_windows.go @@ -22,9 +22,10 @@ var abbrs = map[string]abbr{ "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek "Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion - "Bahia Standard Time": {"BRT", "BRST"}, // America/Bahia + "Bahia Standard Time": {"BRT", "BRT"}, // America/Bahia "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota "Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires + "Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne "Central Standard Time": {"CST", "CDT"}, // America/Chicago @@ -38,21 +39,22 @@ var abbrs = map[string]abbr{ "SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz "Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles "Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City - "Montevideo Standard Time": {"UYT", "UYST"}, // America/Montevideo + "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo "Eastern Standard Time": {"EST", "EDT"}, // America/New_York "US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix "Canada Central Standard Time": {"CST", "CST"}, // America/Regina - "Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Santa_Isabel "Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago "E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo "Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns - "Central Asia Standard Time": {"ALMT", "ALMT"}, // Asia/Almaty + "Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty "Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman "Arabic Standard Time": {"AST", "AST"}, // Asia/Baghdad - "Azerbaijan Standard Time": {"AZT", "AZST"}, // Asia/Baku + "Azerbaijan Standard Time": {"AZT", "AZT"}, // Asia/Baku "SE Asia Standard Time": {"ICT", "ICT"}, // Asia/Bangkok + "Altai Standard Time": {"+06", "+07"}, // Asia/Barnaul "Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut "India Standard Time": {"IST", "IST"}, // Asia/Calcutta + "Transbaikal Standard Time": {"IRKT", "YAKT"}, // Asia/Chita "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka @@ -60,22 +62,26 @@ var abbrs = map[string]abbr{ "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul + "Russia Time Zone 11": {"PETT", "PETT"}, // Asia/Kamchatka "Pakistan Standard Time": {"PKT", "PKT"}, // Asia/Karachi "Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu "North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk "Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan "N. Central Asia Standard Time": {"NOVT", "NOVT"}, // Asia/Novosibirsk + "North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh + "Sakhalin Standard Time": {"SAKT", "SAKT"}, // Asia/Sakhalin "Korea Standard Time": {"KST", "KST"}, // Asia/Seoul "China Standard Time": {"CST", "CST"}, // Asia/Shanghai "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore + "Russia Time Zone 10": {"SRET", "SRET"}, // Asia/Srednekolymsk "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo - "Ulaanbaatar Standard Time": {"ULAT", "ULAT"}, // Asia/Ulaanbaatar + "Ulaanbaatar Standard Time": {"ULAT", "ULAST"}, // Asia/Ulaanbaatar "Vladivostok Standard Time": {"VLAT", "VLAT"}, // Asia/Vladivostok "Yakutsk Standard Time": {"YAKT", "YAKT"}, // Asia/Yakutsk "Ekaterinburg Standard Time": {"YEKT", "YEKT"}, // Asia/Yekaterinburg @@ -83,31 +89,35 @@ var abbrs = map[string]abbr{ "Azores Standard Time": {"AZOT", "AZOST"}, // Atlantic/Azores "Cape Verde Standard Time": {"CVT", "CVT"}, // Atlantic/Cape_Verde "Greenwich Standard Time": {"GMT", "GMT"}, // Atlantic/Reykjavik - "Cen. Australia Standard Time": {"CST", "CST"}, // Australia/Adelaide - "E. Australia Standard Time": {"EST", "EST"}, // Australia/Brisbane - "AUS Central Standard Time": {"CST", "CST"}, // Australia/Darwin - "Tasmania Standard Time": {"EST", "EST"}, // Australia/Hobart - "W. Australia Standard Time": {"WST", "WST"}, // Australia/Perth - "AUS Eastern Standard Time": {"EST", "EST"}, // Australia/Sydney + "Cen. Australia Standard Time": {"ACST", "ACDT"}, // Australia/Adelaide + "E. Australia Standard Time": {"AEST", "AEST"}, // Australia/Brisbane + "AUS Central Standard Time": {"ACST", "ACST"}, // Australia/Darwin + "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart + "W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth + "AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney "UTC": {"GMT", "GMT"}, // Etc/GMT "UTC-11": {"GMT+11", "GMT+11"}, // Etc/GMT+11 "Dateline Standard Time": {"GMT+12", "GMT+12"}, // Etc/GMT+12 "UTC-02": {"GMT+2", "GMT+2"}, // Etc/GMT+2 "UTC+12": {"GMT-12", "GMT-12"}, // Etc/GMT-12 + "Astrakhan Standard Time": {"+03", "+04"}, // Europe/Astrakhan "W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin "GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest "Central Europe Standard Time": {"CET", "CEST"}, // Europe/Budapest + "E. Europe Standard Time": {"EET", "EEST"}, // Europe/Chisinau "Turkey Standard Time": {"EET", "EEST"}, // Europe/Istanbul - "Kaliningrad Standard Time": {"FET", "FET"}, // Europe/Kaliningrad + "Kaliningrad Standard Time": {"EET", "EET"}, // Europe/Kaliningrad "FLE Standard Time": {"EET", "EEST"}, // Europe/Kiev "GMT Standard Time": {"GMT", "BST"}, // Europe/London + "Belarus Standard Time": {"MSK", "MSK"}, // Europe/Minsk "Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow "Romance Standard Time": {"CET", "CEST"}, // Europe/Paris + "Russia Time Zone 3": {"SAMT", "SAMT"}, // Europe/Samara "Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw "Mauritius Standard Time": {"MUT", "MUT"}, // Indian/Mauritius - "Samoa Standard Time": {"WST", "WST"}, // Pacific/Apia + "Samoa Standard Time": {"WSST", "WSDT"}, // Pacific/Apia "New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland - "Fiji Standard Time": {"FJT", "FJT"}, // Pacific/Fiji + "Fiji Standard Time": {"FJT", "FJST"}, // Pacific/Fiji "Central Pacific Standard Time": {"SBT", "SBT"}, // Pacific/Guadalcanal "Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu "Line Islands Standard Time": {"LINT", "LINT"}, // Pacific/Kiritimati From 30fc940c70ee5ee27f0a455248735b8b57f34fb7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 20 May 2016 17:26:24 -0700 Subject: [PATCH 191/267] go/types: don't drop type in n:1 var decl if one is given In n:1 variable declarations (multiple lhs variables with single multi-valued initialization expression) where also a variable type is provided, make sure that that type is assigned to all variables on the lhs before the init expression assignment is checked. Otherwise, (some) variables are assumed to take the type of the corresponding value of the multi-valued init expression. Fixes #15755. Change-Id: I969cb5a95c85e28dbb38abd7fa7df16ff5554c03 Reviewed-on: https://go-review.googlesource.com/23313 Reviewed-by: Alan Donovan --- src/go/types/decl.go | 19 +++++++++++++++++++ src/go/types/testdata/issues.src | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index f064f6856f24f7..1ecfb35f60c3ee 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -141,6 +141,14 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { // determine type, if any if typ != nil { obj.typ = check.typ(typ) + // We cannot spread the type to all lhs variables if there + // are more than one since that would mark them as checked + // (see Checker.objDecl) and the assignment of init exprs, + // if any, would not be checked. + // + // TODO(gri) If we have no init expr, we should distribute + // a given type otherwise we need to re-evalate the type + // expr for each lhs variable, leading to duplicate work. } // check initialization @@ -173,6 +181,17 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { panic("inconsistent lhs") } } + + // We have multiple variables on the lhs and one init expr. + // Make sure all variables have been given the same type if + // one was specified, otherwise they assume the type of the + // init expression values (was issue #15755). + if typ != nil { + for _, lhs := range lhs { + lhs.typ = obj.typ + } + } + check.initVars(lhs, []ast.Expr{init}, token.NoPos) } diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index 4fe0c629386776..6579aa3b117b65 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -170,3 +170,19 @@ func issue14229() { _ = b % a ) } + +// Check that in a n:1 variable declaration with type and initialization +// expression the type is distributed to all variables of the lhs before +// the initialization expression assignment is checked. +func issue15755() { + // from issue + var i interface{} + type b bool + var x, y b = i.(b) + _ = x == y + + // related: we should see an error since the result of f1 is ([]int, int) + var u, v []int = f1 /* ERROR cannot use f1 */ () + _ = u + _ = v +} From 7a9f6c2b56bd87ff7f9296344c9e63cc46194428 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 23 May 2016 13:09:12 -0700 Subject: [PATCH 192/267] cmd/compile: benchmark needs dominator tree Now that CSE uses dom tree to order partitions, we need the dom tree computed before benchmarking CSE. Fixes #15801 Change-Id: Ifa4702c7b75250f34de185e69a880b3f3cc46a12 Reviewed-on: https://go-review.googlesource.com/23361 Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/passbm_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/passbm_test.go b/src/cmd/compile/internal/ssa/passbm_test.go index 8dff17a5b413fb..87069abc3b1b9f 100644 --- a/src/cmd/compile/internal/ssa/passbm_test.go +++ b/src/cmd/compile/internal/ssa/passbm_test.go @@ -35,7 +35,7 @@ func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) { b.ReportAllocs() c := NewConfig("amd64", DummyFrontend{b}, nil, true) fun := Fun(c, "entry", bg(size)...) - + domTree(fun.f) CheckFunc(fun.f) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -51,7 +51,7 @@ func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) { b.ReportAllocs() c := NewConfig("amd64", DummyFrontend{b}, nil, true) fun := Fun(c, "entry", bg(b.N)...) - + domTree(fun.f) CheckFunc(fun.f) b.ResetTimer() for i := 0; i < passCount; i++ { From ab4414773e27624abf4361e48a0ca0979e804970 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 02:45:11 -0400 Subject: [PATCH 193/267] math/big: write t*10 to multiply t by 10 The compiler has caught up. In fact the compiler is ahead; it knows about a magic multiply-by-5 instruction: // compute '0' + byte(r - t*10) in AX MOVQ t, AX LEAQ (AX)(AX*4), AX SHLQ $1, AX MOVQ r, CX SUBQ AX, CX LEAL 48(CX), AX For comparison, the shifty version compiles to: // compute '0' + byte(r - t*10) in AX MOVQ t, AX MOVQ AX, CX SHLQ $3, AX MOVQ r, DX SUBQ AX, DX SUBQ CX, DX SUBQ CX, DX LEAL 48(DX), AX Fixes #2671. Change-Id: Ifbf23dbfeb19c0bb020fa44eb2f025943969fb6b Reviewed-on: https://go-review.googlesource.com/23372 Run-TryBot: Russ Cox Reviewed-by: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/math/big/natconv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go index e216bd288ccd2c..44547842c1ced2 100644 --- a/src/math/big/natconv.go +++ b/src/math/big/natconv.go @@ -391,7 +391,7 @@ func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []diviso // this appears to be faster for BenchmarkString10000Base10 // and smaller strings (but a bit slower for larger ones) t := r / 10 - s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code + s[i] = '0' + byte(r-t*10) r = t } } From 12610236375e2e981e370508548f3d51920df7e2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 May 2016 12:21:57 -0400 Subject: [PATCH 194/267] encoding/json: additional tests and fixes for []typedByte encoding/decoding CL 19725 changed the encoding of []typedByte to look for typedByte.MarshalJSON and typedByte.MarshalText. Previously it was handled like []byte, producing a base64 encoding of the underlying byte data. CL 19725 forgot to look for (*typedByte).MarshalJSON and (*typedByte).MarshalText, as the marshaling of other slices would. Add test and fix for those. This CL also adds tests that the decoder can handle both the old and new encodings. (This was true even in Go 1.6, which is the only reason we can consider this not an incompatible change.) For #13783. Change-Id: I7cab8b6c0154a7f2d09335b7fa23173bcf856c37 Reviewed-on: https://go-review.googlesource.com/23294 Reviewed-by: Ian Lance Taylor Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Andrew Gerrand --- src/encoding/json/decode_test.go | 212 +++++++++++++++++++++++++++++-- src/encoding/json/encode.go | 9 +- 2 files changed, 208 insertions(+), 13 deletions(-) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 7c388c0c272ff6..255ff5c66a75bf 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -238,14 +238,6 @@ type S13 struct { S8 } -type unmarshalTest struct { - in string - ptr interface{} - out interface{} - err error - useNumber bool -} - type Ambig struct { // Given "hello", the first match should win. First int `json:"HELLO"` @@ -261,6 +253,127 @@ type XYZ struct { func sliceAddr(x []int) *[]int { return &x } func mapAddr(x map[string]int) *map[string]int { return &x } +type byteWithMarshalJSON byte + +func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil +} + +func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { + if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[2:4]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = byteWithMarshalJSON(i) + return nil +} + +type byteWithPtrMarshalJSON byte + +func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { + return byteWithMarshalJSON(*b).MarshalJSON() +} + +func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { + return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) +} + +type byteWithMarshalText byte + +func (b byteWithMarshalText) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil +} + +func (b *byteWithMarshalText) UnmarshalText(data []byte) error { + if len(data) != 3 || data[0] != 'Z' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[1:3]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = byteWithMarshalText(i) + return nil +} + +type byteWithPtrMarshalText byte + +func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { + return byteWithMarshalText(*b).MarshalText() +} + +func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { + return (*byteWithMarshalText)(b).UnmarshalText(data) +} + +type intWithMarshalJSON int + +func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil +} + +func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { + if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[2:4]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = intWithMarshalJSON(i) + return nil +} + +type intWithPtrMarshalJSON int + +func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { + return intWithMarshalJSON(*b).MarshalJSON() +} + +func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { + return (*intWithMarshalJSON)(b).UnmarshalJSON(data) +} + +type intWithMarshalText int + +func (b intWithMarshalText) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil +} + +func (b *intWithMarshalText) UnmarshalText(data []byte) error { + if len(data) != 3 || data[0] != 'Z' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[1:3]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = intWithMarshalText(i) + return nil +} + +type intWithPtrMarshalText int + +func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { + return intWithMarshalText(*b).MarshalText() +} + +func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { + return (*intWithMarshalText)(b).UnmarshalText(data) +} + +type unmarshalTest struct { + in string + ptr interface{} + out interface{} + err error + useNumber bool + golden bool +} + var unmarshalTests = []unmarshalTest{ // basic types {in: `true`, ptr: new(bool), out: true}, @@ -547,6 +660,84 @@ var unmarshalTests = []unmarshalTest{ ptr: &map[unmarshaler]string{}, err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1}, }, + + // related to issue 13783. + // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, + // similar to marshaling a slice of typed int. + // These tests check that, assuming the byte type also has valid decoding methods, + // either the old base64 string encoding or the new per-element encoding can be + // successfully unmarshaled. The custom unmarshalers were accessible in earlier + // versions of Go, even though the custom marshaler was not. + { + in: `"AQID"`, + ptr: new([]byteWithMarshalJSON), + out: []byteWithMarshalJSON{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithMarshalJSON), + out: []byteWithMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithMarshalText), + out: []byteWithMarshalText{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithMarshalText), + out: []byteWithMarshalText{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithPtrMarshalJSON), + out: []byteWithPtrMarshalJSON{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithPtrMarshalJSON), + out: []byteWithPtrMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithPtrMarshalText), + out: []byteWithPtrMarshalText{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithPtrMarshalText), + out: []byteWithPtrMarshalText{1, 2, 3}, + golden: true, + }, + + // ints work with the marshaler but not the base64 []byte case + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithMarshalJSON), + out: []intWithMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithMarshalText), + out: []intWithMarshalText{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithPtrMarshalJSON), + out: []intWithPtrMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithPtrMarshalText), + out: []intWithPtrMarshalText{1, 2, 3}, + golden: true, + }, } func TestMarshal(t *testing.T) { @@ -680,13 +871,16 @@ func TestUnmarshal(t *testing.T) { continue } - // Check round trip. + // Check round trip also decodes correctly. if tt.err == nil { enc, err := Marshal(v.Interface()) if err != nil { t.Errorf("#%d: error re-marshaling: %v", i, err) continue } + if tt.golden && !bytes.Equal(enc, in) { + t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) + } vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) dec = NewDecoder(bytes.NewReader(enc)) if tt.useNumber { diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index f91a78724cf44d..3917084dc3324a 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -698,10 +698,11 @@ func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { func newSliceEncoder(t reflect.Type) encoderFunc { // Byte slices get special treatment; arrays don't. - if t.Elem().Kind() == reflect.Uint8 && - !t.Elem().Implements(marshalerType) && - !t.Elem().Implements(textMarshalerType) { - return encodeByteSlice + if t.Elem().Kind() == reflect.Uint8 { + p := reflect.PtrTo(t.Elem()) + if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) { + return encodeByteSlice + } } enc := &sliceEncoder{newArrayEncoder(t)} return enc.encode From 8e724e7bbad07d530f547b6214c71ddfe26ba92a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 May 2016 20:34:39 -0400 Subject: [PATCH 195/267] cmd/go: fix //go:binary-only-package check The use of a prefix check was too liberal. Noted in review after submit. Change-Id: I4fe1df660997efd225609e818040b8392fab79f0 Reviewed-on: https://go-review.googlesource.com/23375 Run-TryBot: Russ Cox Reviewed-by: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/cmd/go/go_test.go | 3 ++- src/go/build/build.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index b6673967619374..987021ecca97b0 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2804,7 +2804,8 @@ func TestBinaryOnlyPackages(t *testing.T) { os.Remove(tg.path("src/p1/p1.go")) tg.mustNotExist(tg.path("src/p1/p1.go")) - tg.tempFile("src/p2/p2.go", ` + tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great + package p2 import "p1" func F() { p1.F(true) } diff --git a/src/go/build/build.go b/src/go/build/build.go index fa258d3dc671a4..9706b8b6b31d62 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -1151,7 +1151,7 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binary } line = bytes.TrimSpace(line) if bytes.HasPrefix(line, slashslash) { - if bytes.HasPrefix(line, binaryOnlyComment) { + if bytes.Equal(line, binaryOnlyComment) { sawBinaryOnly = true } line = bytes.TrimSpace(line[len(slashslash):]) From 7f9255c2120f784c334431661145ee89e75f64fe Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 May 2016 20:40:52 -0400 Subject: [PATCH 196/267] net: revise IP.String result for malformed IP address to add ? back In earlier versions of Go the result was simply "?". A change in this cycle made the result echo back the hex bytes of the address, which is certainly useful, but now the result is not clearly indicating an error. Put the "?" back, at the beginning of the hex string, to make the invalidity of the string clearer. Change-Id: I3e0f0b6a005601cd98d982a62288551959185b40 Reviewed-on: https://go-review.googlesource.com/23376 Run-TryBot: Russ Cox Reviewed-by: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/net/ip.go | 4 ++-- src/net/ip_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net/ip.go b/src/net/ip.go index 06d349b5f2c3d0..d0c82630b57830 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -272,7 +272,7 @@ func (ip IP) String() string { uitoa(uint(p4[3])) } if len(p) != IPv6len { - return hexString(ip) + return "?" + hexString(ip) } // Find longest run of zeros. @@ -338,7 +338,7 @@ func (ip IP) MarshalText() ([]byte, error) { return []byte(""), nil } if len(ip) != IPv4len && len(ip) != IPv6len { - return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()} + return nil, &AddrError{Err: "invalid IP address", Addr: hexString(ip)} } return []byte(ip.String()), nil } diff --git a/src/net/ip_test.go b/src/net/ip_test.go index 87c12133c33567..b6ac26da05b84a 100644 --- a/src/net/ip_test.go +++ b/src/net/ip_test.go @@ -225,7 +225,7 @@ var ipStringTests = []struct { // Opaque byte sequence { IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, - "0123456789abcdef", + "?0123456789abcdef", nil, &AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"}, }, From 658814fa386a08761032b659f64f4eecb79ca084 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 02:25:56 -0400 Subject: [PATCH 197/267] A+C: add Andre Nathan (individual CLA) Andre wrote https://golang.org/cl/13454043 (never submitted), which served as the basis for Ross Light's https://golang.org/cl/19235. Individual CLA verified by hand. Change-Id: Ic09e8efd84b7ded3ae472c204133e40cb85d97f7 Reviewed-on: https://go-review.googlesource.com/23377 Run-TryBot: Russ Cox Reviewed-by: Andrew Gerrand TryBot-Result: Gobot Gobot --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index bebe250458d048..d6b72718bcc4ad 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,6 +58,7 @@ Alif Rachmawadi Amazon.com, Inc Amir Mohammad Saied Amrut Joshi +Andre Nathan Andrei Korzhevskii Andrei Vieru Andrew Balholm diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4d0863b3efe76c..6845a392680b61 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -86,6 +86,7 @@ Aliaksandr Valialkin Alif Rachmawadi Amir Mohammad Saied Amrut Joshi +Andre Nathan Andrea Spadaccini Andreas Jellinghaus Andrei Korzhevskii From 4aea7a12b6a6621a67267050df0688f28adfe6b4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 May 2016 11:41:00 -0400 Subject: [PATCH 198/267] encoding/json: change DisableHTMLEscaping to SetEscapeHTML DisableHTMLEscaping is now SetEscapeHTML, allowing the escaping to be toggled, not just disabled. This API is new for Go 1.7, so there are no compatibility concerns (quite the opposite, the point is to fix the API before we commit to it in Go 1.7). Change-Id: I96b9f8f169a9c44995b8a157a626eb62d0b6dea7 Reviewed-on: https://go-review.googlesource.com/23293 Reviewed-by: Ian Lance Taylor Reviewed-by: Andrew Gerrand --- src/encoding/json/stream.go | 13 +++++++++---- src/encoding/json/stream_test.go | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go index d6b2992e9be1c3..dba978aa662433 100644 --- a/src/encoding/json/stream.go +++ b/src/encoding/json/stream.go @@ -226,10 +226,15 @@ func (enc *Encoder) Indent(prefix, indent string) { enc.indentValue = indent } -// DisableHTMLEscaping causes the encoder not to escape angle brackets -// ("<" and ">") or ampersands ("&") in JSON strings. -func (enc *Encoder) DisableHTMLEscaping() { - enc.escapeHTML = false +// SetEscapeHTML specifies whether problematic HTML characters +// should be escaped inside JSON quoted strings. +// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e +// to avoid certain safety problems that can arise when embedding JSON in HTML. +// +// In non-HTML settings where the escaping interferes with the readability +// of the output, SetEscapeHTML(false) disables this behavior. +func (enc *Encoder) SetEscapeHTML(on bool) { + enc.escapeHTML = on } // RawMessage is a raw encoded JSON value. diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go index 3516ac3b83d971..0d578ce24dadf6 100644 --- a/src/encoding/json/stream_test.go +++ b/src/encoding/json/stream_test.go @@ -87,7 +87,7 @@ func TestEncoderIndent(t *testing.T) { } } -func TestEncoderDisableHTMLEscaping(t *testing.T) { +func TestEncoderSetEscapeHTML(t *testing.T) { var c C var ct CText for _, tt := range []struct { @@ -109,12 +109,12 @@ func TestEncoderDisableHTMLEscaping(t *testing.T) { t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape) } buf.Reset() - enc.DisableHTMLEscaping() + enc.SetEscapeHTML(false) if err := enc.Encode(tt.v); err != nil { - t.Fatalf("DisableHTMLEscaping Encode(%s): %s", tt.name, err) + t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err) } if got := strings.TrimSpace(buf.String()); got != tt.want { - t.Errorf("DisableHTMLEscaping Encode(%s) = %#q, want %#q", + t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q", tt.name, got, tt.want) } } From 34b17d4dc5726eebde437f2c1b680d039cc3e7c0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 May 2016 12:28:56 -0400 Subject: [PATCH 199/267] encoding/json: rename Indent method to SetIndent CL 21057 added this method during the Go 1.7 cycle (so it is not yet released and still possible to revise). This makes it clearer that the method is not doing something (like func Indent does), but just changing a setting about doing something later. Also document that this is in some sense irreversible. I think that's probably a mistake but the original CL discussion claimed it as a feature, so I'll leave it alone. For #6492. Change-Id: If4415c869a9196501056c143811a308822d5a420 Reviewed-on: https://go-review.googlesource.com/23295 Reviewed-by: Ian Lance Taylor Reviewed-by: Andrew Gerrand Run-TryBot: Russ Cox --- src/encoding/json/stream.go | 14 +++++++++----- src/encoding/json/stream_test.go | 5 ++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go index dba978aa662433..87f0e57c6cdb5c 100644 --- a/src/encoding/json/stream.go +++ b/src/encoding/json/stream.go @@ -204,7 +204,10 @@ func (enc *Encoder) Encode(v interface{}) error { e.WriteByte('\n') b := e.Bytes() - if enc.indentBuf != nil { + if enc.indentPrefix != "" || enc.indentValue != "" { + if enc.indentBuf == nil { + enc.indentBuf = new(bytes.Buffer) + } enc.indentBuf.Reset() err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) if err != nil { @@ -219,9 +222,10 @@ func (enc *Encoder) Encode(v interface{}) error { return err } -// Indent sets the encoder to format each encoded value with Indent. -func (enc *Encoder) Indent(prefix, indent string) { - enc.indentBuf = new(bytes.Buffer) +// SetIndent instructs the encoder to format each subsequent encoded +// value as if indented by the package-level function Indent(dst, src, prefix, indent). +// Calling SetIndent("", "") disables indentation. +func (enc *Encoder) SetIndent(prefix, indent string) { enc.indentPrefix = prefix enc.indentValue = indent } @@ -230,7 +234,7 @@ func (enc *Encoder) Indent(prefix, indent string) { // should be escaped inside JSON quoted strings. // The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e // to avoid certain safety problems that can arise when embedding JSON in HTML. -// +// // In non-HTML settings where the escaping interferes with the readability // of the output, SetEscapeHTML(false) disables this behavior. func (enc *Encoder) SetEscapeHTML(on bool) { diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go index 0d578ce24dadf6..84edeb187c2592 100644 --- a/src/encoding/json/stream_test.go +++ b/src/encoding/json/stream_test.go @@ -44,6 +44,9 @@ func TestEncoder(t *testing.T) { for i := 0; i <= len(streamTest); i++ { var buf bytes.Buffer enc := NewEncoder(&buf) + // Check that enc.SetIndent("", "") turns off indentation. + enc.SetIndent(">", ".") + enc.SetIndent("", "") for j, v := range streamTest[0:i] { if err := enc.Encode(v); err != nil { t.Fatalf("encode #%d: %v", j, err) @@ -77,7 +80,7 @@ false func TestEncoderIndent(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) - enc.Indent(">", ".") + enc.SetIndent(">", ".") for _, v := range streamTest { enc.Encode(v) } From 85e3c9e6b863792135c8cd49bebfd1028e87cee5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 02:52:31 -0400 Subject: [PATCH 200/267] cmd/compile, go/types: omit needless word in error message CL 21462 and CL 21463 made this message say explicitly that the problem was a struct field in a map, but the word "directly" is unnecessary, sounds wrong, and makes the error long. Change-Id: I2fb68cdaeb8bd94776b8022cf3eae751919ccf6f Reviewed-on: https://go-review.googlesource.com/23373 Run-TryBot: Russ Cox Reviewed-by: David Chase --- src/cmd/compile/internal/gc/typecheck.go | 2 +- src/go/types/assignments.go | 2 +- src/go/types/testdata/stmt0.src | 2 +- test/fixedbugs/issue13779.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 5c23d08cf36ccc..ffd4afcc01137e 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -3153,7 +3153,7 @@ func checkassign(stmt *Node, n *Node) { } if n.Op == ODOT && n.Left.Op == OINDEXMAP { - Yyerror("cannot directly assign to struct field %v in map", n) + Yyerror("cannot assign to struct field %v in map", n) return } diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index c7564bcf85d355..6ebf3b5eab0745 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -183,7 +183,7 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type { var op operand check.expr(&op, sel.X) if op.mode == mapindex { - check.errorf(z.pos(), "cannot directly assign to struct field %s in map", ExprString(z.expr)) + check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr)) return nil } } diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src index ac32ed7ba92f32..0c727c3dd011a9 100644 --- a/src/go/types/testdata/stmt0.src +++ b/src/go/types/testdata/stmt0.src @@ -137,7 +137,7 @@ func issue6487() { type M map[string]S var m M - m /* ERROR "cannot directly assign to struct field" */ ["foo"].x = 0 + m /* ERROR "cannot assign to struct field" */ ["foo"].x = 0 _ = &( /* ERROR "cannot take address" */ m["foo"].x) _ = &m /* ERROR "cannot take address" */ ["foo"].x } diff --git a/test/fixedbugs/issue13779.go b/test/fixedbugs/issue13779.go index 94cf9c68de0fe9..b18577c1528496 100644 --- a/test/fixedbugs/issue13779.go +++ b/test/fixedbugs/issue13779.go @@ -11,5 +11,5 @@ package main func main() { type person struct{ age, weight, height int } students := map[string]person{"sally": person{12, 50, 32}} - students["sally"].age = 3 // ERROR "cannot directly assign to struct field .* in map" + students["sally"].age = 3 // ERROR "cannot assign to struct field .* in map" } From f117a5359af607d8e62fa9cd66eb327d18a7d6d7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 03:12:41 -0400 Subject: [PATCH 201/267] doc: first draft of Go 1.7 release notes Mostly complete but a few TODOs remain for future CLs. For #15810. Change-Id: I81ee19d1088d192cf709a5f7e6b7bcc44ad892ac Reviewed-on: https://go-review.googlesource.com/23379 Reviewed-by: Andrew Gerrand Run-TryBot: Russ Cox --- doc/go1.7.html | 1122 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/go1.7.txt | 36 -- 2 files changed, 1122 insertions(+), 36 deletions(-) create mode 100644 doc/go1.7.html delete mode 100644 doc/go1.7.txt diff --git a/doc/go1.7.html b/doc/go1.7.html new file mode 100644 index 00000000000000..74607d7ca5f606 --- /dev/null +++ b/doc/go1.7.html @@ -0,0 +1,1122 @@ + + + + + + + + +

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

+ +

Introduction to Go 1.7

+ +

+The latest Go release, version 1.7, arrives six months after 1.6. +Most of its changes are in the implementation of the toolchain, runtime, and libraries. +There is one minor change to the language specification. +As always, the release maintains the Go 1 promise of compatibility. +We expect almost all Go programs to continue to compile and run as before. +

+ +

+The release adds a port to IBM LinuxOne; +updates the x86-64 compiler back end to generate more efficient code; +includes the context package, promoted from the +x/net subrepository +and now used throughout the standard library; +and adds support in the testing package for +creating hierarchies of tests and benchmarks. +The release also removes the ability to disable +the vendoring changes started in Go 1.5: +vendoring is now an official part of the Go toolchain. +

+ +

Changes to the language

+ +

+There is one tiny language change in this release. +The section on terminating statements +clarifies that to determine whether a statement list ends in a terminating statement, +the “final non-empty statement” is considered the end, +matching the existing behavior of the gc and gccgo compiler toolchains. +In earlier releases the definition referred only to the “final statement,” +leaving the effect of trailing empty statements at the least unclear. +The go/types +package has been updated to match the gc and gccgo compiler toolchains +in this respect. +

+ +

Ports

+ +

+Go 1.7 adds an experimental port to Linux on z Systems (linux/s390x) +and the beginning of a port to Plan 9 on ARM (plan9/arm). +

+ +

+The experimental ports to Linux on 64-bit MIPS (linux/mips64 and linux/mips64le) +added in Go 1.6 now have full support for cgo and external linking. +

+ +

+The experimental port to Linux on big-endian 64-bit PowerPC (linux/ppc64) +now requires the POWER8 architecture or later. +TODO: Pending ppc64le change for cgo. +

+ +

+The OpenBSD port now requires OpenBSD 5.6 or later, for access to the getentropy(2) system call. +

+ +

Tools

+ +

Assembler

+ +

+For 64-bit ARM systems, the vector register names have been +corrected to V0 through V31; +previous releases incorrectly referred to them as V32 through V63. +

+ +

+For 64-bit x86 systems, the following instructions have been added: +PCMPESTRI, +RORXL, +RORXQ, +VINSERTI128, +VPADDD, +VPADDQ, +VPALIGNR, +VPBLENDD, +VPERM2F128, +VPERM2I128, +VPOR, +VPSHUFB, +VPSHUFD, +VPSLLD, +VPSLLDQ, +VPSLLQ, +VPSRLD, +VPSRLDQ, +and +VPSRLQ. +

+ +

Compiler Toolchain

+ +

+This release includes a new code generation back end for 64-bit x86 systems, +following a proposal from 2015 +that has been under development since then. +The new back end, based on +SSA, +generates more compact, more efficient code +and provides a better platform for optimizations +such as bounds check elimination. +The new back end reduces the CPU time required by our benchmark programs by 5-35%. +

+ +

+For this release, the new back end can be disabled by passing +-ssa=0 to the compiler. +If you find that your program compiles or runs successfully +only with the new back end disabled, please +file a bug report. +

+ +

+The format of exported metadata written by the compiler in package archives has changed: +the old textual format has been replaced by a more compact binary format. +This results in somewhat smaller package archives and fixes a few +long-standing corner case bugs. +

+ +

+For this release, the new export format can be disabled by passing +-newexport=0 to the compiler. +If you find that your program compiles or runs successfully +only with the new export format disabled, please +file a bug report. +

+ +

+The linker's -X option no longer supports the unusual two-argument form +-X name value, +as announced in the Go 1.6 release +and in warnings printed by the linker. +Use -X name=value instead. +

+ +

+The compiler and linker have been optimized and run significantly faster in this release than in Go 1.6, +although they are still slower than we would like and will continue to be optimized in future releases. +

+ +

+Due to changes across the compiler toolchain and standard library, +binaries built with this release should typically be smaller than binaries +built with Go 1.6, +sometimes by as much as 20-30%. +

+ +

Cgo

+ +

+Packages using cgo may now include +Fortran source files (in addition to C, C++, Objective C, and SWIG), +although the Go bindings must still use C language APIs. +

+ +

+Go bindings may now use a new helper function C.CBytes. +In contrast to C.CString, which takes a Go string +and returns a *C.byte (a C char*), +C.CBytes takes a Go []byte +and returns an unsafe.Pointer (a C void*). +

+ +

+Packages and binaries built using cgo have in past releases +produced different output on each build, +due to the embedding of temporary directory names. +When using this release with +new enough versions of GCC or Clang +(those that support the -fdebug-prefix-map option), +those builds should finally be deterministic. +

+ +

Gccgo

+ +

+Due to the alignment of Go's semiannual release schedule with GCC's annual release schedule, +GCC release 6 contains the Go 1.6.1 version of gccgo. +The next release, GCC 7, will likely have the Go 1.8 version of gccgo. +

+ +

Go command

+ +

+The go command's basic operation +is unchanged, but there are a number of changes worth noting. +

+ +

+This release removes support for the GO15VENDOREXPERIMENT environment variable, +as announced in the Go 1.6 release. +Vendoring support +is now a standard feature of the go command and toolchain. +

+ +

+The Package data structure made available to +“go list” now includes a +StaleReason field explaining why a particular package +is or is not considered stale (in need of rebuilding). +This field is available to the -f or -json +options and is useful for understanding why a target is being rebuilt. +

+ +

+The “go get” command now supports +import paths referring to git.openstack.org. +

+ +

+This release adds experimental, minimal support for building programs using +binary-only packages, +packages distributed in binary form +without the corresponding source code. +This feature is needed in some commercial settings +but is not intended to be fully integrated into the rest of the toolchain. +For example, tools that assume access to complete source code +will not work with such packages, and there are no plans to support +such packages in the “go get” command. +

+ +

Go doc

+ +

+The “go doc” command +now groups constructors with the type they construct, +following godoc. +

+ +

Go vet

+ +

+The “go vet” command +has more accurate analysis in its -copylock and -printf checks, +and a new -tests check that checks the name and signature of likely test functions. +To avoid confusion with the new -tests check, the old, unadvertised +-test option has been removed; it was equivalent to -all -shadow. +

+ +

Go tool dist

+ +

+The new subcommand “go tool dist list” +prints all supported operating system/architecture pairs. +

+ +

Go tool trace

+ +

+The “go tool trace” command, +introduced in Go 1.5, +has been refined in various ways. +

+ +

+First, collecting traces is significantly more efficient than in past releases. +In this release, the typical execution-time overhead of collecting a trace is about 25%; +in past releases it was at least 400%. +Second, trace files now include file and line number information, +making them more self-contained and making the +original executable optional when running the trace tool. +Third, the trace tool now breaks up large traces to avoid limits +in the browser-based viewer. +

+ +

+Although the trace file format has changed in this release, +the Go 1.7 tools can still read traces from earlier releases. +

+ +

Performance

+ +

+As always, the changes are so general and varied that precise statements +about performance are difficult to make. +Most programs should run a bit faster, +due to speedups in the garbage collector and +optimizations in the core library. +On x86-64 systems, many programs will run significantly faster, +due to improvements in generated code brought by the +new compiler back end. +As noted above, in our own benchmarks, +the code generation changes alone typically reduce program CPU time by 5-35%. +

+ +

+ +There have been significant optimizations bringing more than 10% improvements +to implementations in the +crypto/sha1, +crypto/sha256, +encoding/binary, +fmt, +hash/adler32, +hash/crc32, +hash/crc64, +image/color, +math/big, +strconv, +strings, +unicode, +and +unicode/utf16 +packages. +

+ +

Core library

+ +

Context

+ +

+Go 1.7 moves the golang.org/x/net/context package +into the standard library as context. +This allows the use of contexts for cancellation, timeouts, and passing +request-scoped data in other standard library packages, +including +net, +net/http, +and +os/exec, +as noted below. +

+ +

+TODO: Example here. +

+ +

+For more information about contexts, see the +package documentation +and the Go blog post +“Go Concurrent Patterns: Context.” +

+ +

Testing

+ +

+The testing package now supports the definition +of tests with subtests and benchmarks with sub-benchmarks. +

+ +

+TODO: Where is the documentation for this? +

+ +

+TODO: Example here. +

+ +

Runtime

+ +

+All panics started by the runtime now use panic values +that implement both the builtin error, +and +runtime.Error, +as +required by the language specification. +

+ +

+The new function +KeepAlive +provides an explicit mechanism for declaring +that an allocated object is currently reachable, +typically to delay the execution of an associated finalizer. +

+ +

+The new function +CallersFrames +translates a PC slice obtained from +Callers +into a sequence of frames corresponding to the call stack. +This new API should be preferred instead of direct use of +FuncForPC, +because the frame sequence can more accurately describe +call stacks with inlined function calls. +

+ +

+The new function +SetCgoTraceback +facilitates tighter integration between Go and C code executing +in the same process called using cgo. +

+ +

+On 32-bit systems, the runtime can now use memory allocated +by the operating system anywhere in the address space, +eliminating the +“memory allocated by OS not in usable range” failure +common in some environments. +

+ +

+On Windows, Go programs in Go 1.5 and earlier forced +the global Windows timer resolution to 1ms at startup +by calling timeBeginPeriod(1). +Changing the global timer resolution caused problems on some systems, +and testing suggested that the call was not needed for good scheduler performance, +so Go 1.6 removed the call. +Go 1.7 brings the call back: under some workloads the call +is still needed for good scheduler performance. +

+ + +

Minor changes to the library

+ +

+As always, there are various minor changes and updates to the library, +made with the Go 1 promise of compatibility +in mind. +

+ +
bufio
+ +
+

+In previous releases of Go, if +Reader's +Peek method +were asked for more bytes than fit in the underlying buffer, +it would return an empty slice and the error ErrBufferFull. +Now it returns the entire underlying buffer, still accompanied by the error ErrBufferFull. +

+
+ +
bytes
+ +
+

+The new functions +ContainsAny and +ContainsRune +have been added for symmetry with +the strings package. +

+ +

+In previous releases of Go, if +Reader's +Read method +were asked for zero bytes with no data remaining, it would +return a count of 0 and no error. +Now it returns a count of 0 and the error +io.EOF . +

+ +

+The +Reader type has a new method +Reset to allow reuse of a Reader. +

+
+ +
compress/flate
+ +
+

+As noted above, +there are significant performance optimizations throughout the package. +Decompression speed is improved by about 10%, +while compression speed for DefaultCompression is roughly doubled. +

+ +

+In addition to those general improvements, +the +BestSpeed +compressor has been replaced entirely and uses an +algorithm similar to Snappy, +resulting in about a 2.5X speed increase, +although the output can be 5-10% larger than with the previous algorithm. +

+ +

+There is also a new compression level +HuffmanOnly +that applies Huffman but not Lempel-Ziv encoding. +Forgoing Lempel-Ziv encoding means that +HuffmanOnly runs about 3X faster than the new BestSpeed +but at the cost of producing compressed outputs that are 20-40% larger than those +generated by the new BestSpeed. +

+
+ +
crypto/tls
+ +
+

+TODO: Describe Config.DynamicRecordSizingDisabled or whatever replaces it. +

+ +

+The TLS client now has optional, limited support for server-initiated renegotiation, +enabled by setting the +Config's +Renegotiation field. +This is needed for connecting to many Microsoft Azure servers. +

+ +

+The errors returned by the package now consistently begin with a +tls: prefix. +In past releases, some errors used a crypto/tls: prefix, +some used a tls: prefix, and some had no prefix at all. +

+ +

+When generating self-signed certificates, the package no longer sets the +“Authority Key Identifier” field by default. +

+
+ +
crypto/x509
+ +
+

+The new function +SystemCertPool +provides access to the entire system certificate pool if available. +There is also a new associated error type +SystemRootsError. +

+
+ +
debug/dwarf
+ +
+

+The +Reader type's new +SeekPC method and the +Data type's new +Ranges method +help to find the compilation unit to pass to a +LineReader +and to identify the specific function for a given program counter. +

+
+ +
debug/elf
+ +
+

+The new +R_390 relocation type +and its many predefined constants +support the S390 port. +

+
+ +
encoding/asn1
+ +
+

+The ASN.1 decoder now rejects non-minimal integer encodings. +This may cause the package to reject some invalid but formerly accepted ASN.1 data. +

+
+ +
encoding/json
+ +
+

+The +Encoder's new +SetIndent method +sets the indentation parameters for JSON encoding, +like in the top-level +Indent function. +

+ +

+The +Encoder's new +SetEscapeHTML method +controls whether the +&, <, and > +characters in quoted strings should be escaped as +\u0026, \u003c, and \u003e, +respectively. +As in previous releases, the encoder defaults to applying this escaping, +to avoid certain problems that can arise when embedding JSON in HTML. +

+ +

+In earlier versions of Go, this package only supported encoding and decoding +maps using keys with string types. +Go 1.7 adds support for maps using keys with integer types: +the encoding uses a quoted decimal representation as the JSON key. +Go 1.7 also adds support for encoding maps using non-string keys that implement +MarshalJSON +(see +Marshaler) +or +MarshalText +(see +encoding.TextMarshaler) +methods, +as well as support for decoding maps using non-string keys that implement +UnmarshalJSON +(see +Unmarshaler) +or +UnmarshalText +(see +encoding.TextUnmarshaler) +methods. +These methods are ignored for keys with string types in order to preserve +the encoding and decoding used in earlier versions of Go. +

+ +

+When encoding a slice of typed bytes, +Marshal +now generates an array of elements encoded using +that byte type's +MarshalJSON +or +MarshalText +method if present, +only falling back to the default base64-encoded string data if neither method is available. +Earlier versions of Go accept both the original base64-encoded string encoding +and the array encoding (assuming the byte type also implements +UnmarshalJSON +or +UnmarshalText +as appropriate), +so this change should be semantically backwards compatible with earlier versions of Go, +even though it does change the chosen encoding. +

+
+ +
go/build
+ +
+

+To implement the go command's new support for binary-only packages +and for Fortran code in cgo-based packages, +the +Package type +adds new fields BinaryOnly, CgoFFLAGS, and FFiles. +

+
+ +
go/doc
+ +
+

+To support the corresponding change in go test described above, +Example struct adds a Unordered field +indicating whether the example may generate its output lines in any order. +

+
+ +
io
+ +
+

+The package adds new constants +SeekStart, SeekCurrent, and SeekEnd, +for use with +Seeker +implementations. +These constants are preferred over os.SEEK_SET, os.SEEK_CUR, and os.SEEK_END, +but the latter will be preserved for compatibility. +

+
+ +
math/big
+ +
+

+The +Float type adds +GobEncode and +GobDecode methods, +so that values of type Float can now be encoded and decoded using the +encoding/gob +package. +

+
+ +
mime/multipart
+ +
+

+The +Writer +implementation now emits each multipart section's header sorted by key. +Previously, iteration over a map caused the section header to use a +non-deterministic order. +

+
+ +
net
+ +
+

+As part of the introduction of context, the +Dialer type has a new method +DialContext, like +Dial but adding the +context.Context +for the dial operation. +The context is intended to obsolete the Dialer's +Cancel and Deadline fields, +but the implementation continues to respect them, +for backwards compatibility. +

+ +

+The +IP type's +String method has changed its result for invalid IP addresses. +In past releases, if an IP byte slice had length other than 0, 4, or 16, String +returned "?". +Go 1.7 adds the hexadecimal encoding of the bytes, as in "?12ab". +

+ +

+The pure Go name resolution +implementation now respects nsswtch.conf's +stated preference for the priority of DNS lookups compared to +local file (that is, /etc/hosts) lookups. +

+
+ +
net/http
+ +
+

+ResponseWriter's +documentation now makes clear that beginning to write the response +may prevent future reads on the request body. +For maximal compatibility, implementations are encouraged to +read the request body completely before writing any part of the response. +

+ +

+As part of the introduction of context, the +Request has a new methods +Context, to retrieve the associated context, and +WithContext, to construct a copy of Request +with a modified context. +

+ +

+In the +Server implementation, +Serve records in the request context +both the underlying *Server using the key ServerContextKey +and the local address on which the request was received (a +Addr) using the key LocalAddrContextKey. +For example, the address on which a request received is +req.Context().Value(http.LocalAddrContextKey).(net.Addr). +

+ +

+The server implementation now +pads response codes less than 100 to three digits +as required by the protocol, +so that w.WriteHeader(5) uses the HTTP response +status 005, not just 5. +

+ +

+In the client, the +Transport implementation passes the request context +to any dial operation connecting to the remote server. +If a custom dialer is needed, the new Transport field +Dialer is preferred over the existing Dial field, +because the former can accept a context. +

+ +

+The +Transport also adds fields +IdleConnTimeout, +MaxIdleConns, +and +MaxResponseHeaderBytes +to help control client resources consumed +by idle or chatty servers. +

+ +

+A +Client's configured CheckRedirect function can now +return ErrUseLastResponse to indicate that the +most recent redirect response should be returned as the +result of the HTTP request. +That response is now available to the CheckRedirect function +as req.Response. +

+ +

+Since Go 1, the default behavior of the HTTP client is +to request server-side compression +using the Accept-Encoding request header +and then to uncompress the response body transparently, +and this behavior is adjustable using the +Transport's DisableCompression field. +In Go 1.7, to aid the implementation of HTTP proxies, the +Response's new +Uncompressed field reports whether +this transparent uncompression took place. +

+ +

+DetectContentType +adds support for a few new audio and video content types. +

+
+ +
net/http/cgi
+ +
+

+The +Handler +adds a new field +Stderr +that allows redirection of the child process's +standard error away from the host process's +standard error. +

+
+ +
net/http/httptest
+ +
+

+The new function +NewRequest +prepares a new +http.Request +suitable for passing to an +http.Handler during a test. +

+ +

+The +ResponseRecorder's new +Result method +returns the recorded +http.Response. +Tests that need to check the response's headers or trailers +should call Result and inspect the response fields +instead of accessing +ResponseRecorder's HeaderMap directly. +

+
+ +
net/http/httputil
+ +
+

+The +ReverseProxy implementation now responds with “502 Bad Gateway” +when it cannot reach a back end; in earlier releases it responded with “500 Internal Server Error.” +

+ +

+Both +ClientConn and +ServerConn have been documented as deprecated. +They are low-level, old, and unused by Go's current HTTP stack +and will no longer be updated. +Programs should use +http.Client, +http.Transport, +and +http.Server +instead. +

+
+ +
net/http/pprof
+ +
+

+The runtime trace HTTP handler, installed to handle the path /debug/pprof/trace, +now accepts a fractional number in its seconds query parameter, +allowing collection of traces for intervals smaller than one second. +This is especially useful on busy servers. +

+
+ +
net/mail
+ +
+

+The address parser now allows unescaped UTF-8 text in addresses +following RFC 6532, +but it does not apply any normalization to the result. +For compatibility with older mail parsers, +the address encoder, namely +Address's +String method, +continues to escape all UTF-8 text following RFC 5322, +

+
+ +
net/url
+ +
+

+The +URL's +new ForceQuery field +records whether the URL must have a query string, +in order to distinguish URLs without query strings (like /search) +from URLs with empty query strings (like /search?). +

+
+ +
os
+ +
+

+The +File +type adds a new +Size +method, so that File implements the new +SizedReaderAt method. +

+ +

+IsExists now returns true for syscall.ENOTEMPTY, +on systems where that error exists. +

+ +

+On Windows, +Remove now removes read-only files when possible, +making the implementation behave as on +non-Windows systems. +

+
+ +
os/exec
+ +
+

+As part of the introduction of context, +the new constructor +CommandContext +is like +Command but includes a context that can be used to cancel the command execution. +

+
+ +
os/user
+ +
+

+The +Current +function is now implemented even when cgo is not available. +

+ +

+The new +Group type, +along with the lookup functions +LookupGroup and +LookupGroupId +and the new field GroupIds in the User struct, +provides access to system-specific user group information. +

+
+ +
reflect
+ +
+

+Although +Value's +Field method has always been documented to panic +if the given field number i is out of range, it has instead +silently returned a zero +Value. +Go 1.7 changes the method to behave as documented. +

+ +

+The new +StructOf +function constructs a struct type at run time. +It completes the set of type constructors, joining +ArrayOf, +ChanOf, +FuncOf, +MapOf, +PtrTo, +and +SliceOf. +

+ +

+StructTag's +new method +Lookup +is like +Get +but distinguishes the tag not containing the given key +from the tag associating an empty string with the given key. +

+
+ +
strings
+ +
+

+In previous releases of Go, if +Reader's +Read method +were asked for zero bytes with no data remaining, it would +return a count of 0 and no error. +Now it returns a count of 0 and the error +io.EOF . +

+ +

+The +Reader type has a new method +Reset to allow reuse of a Reader. +

+
+ +
text/scanner
+ +
+

+TODO: Describe whatever the final state is after golang.org/issue/15813 is resolved. +

+
+ +
time
+ +
+

+Duration's +time.Duration.String method now reports the zero duration as "0s", not "0". +ParseDuration continues to accept both forms. +

+ +

+The method call time.Local.String() now returns "Local" on all systems; +in earlier releases, it returned an empty string on Windows. +

+ +

+The time zone database in +$GOROOT/lib/time has been updated +to IANA release 2016d. +This fallback database is only used when the system time zone database +cannot be found, for example on Windows. +The Windows time zone abbreviation list has also been updated. +

+
+ +
syscall
+ +
+

+On Linux, the +SysProcAttr struct +(as used in +os/exec.Cmd's SysProcAttr field) +has a new Unshare field. +If the field is nonzero, the child process created by +ForkExec +(as used in exec.Cmd's Run method) +will call the +unshare(2) +system call before executing the new program. +

+
diff --git a/doc/go1.7.txt b/doc/go1.7.txt deleted file mode 100644 index cf24eeffa019ab..00000000000000 --- a/doc/go1.7.txt +++ /dev/null @@ -1,36 +0,0 @@ -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/doc: group constructors with types (CL 22354) -cmd/go, go/build: binary-only package support (CL 22433) -cmd/trace: file:line is embed into traces (CL 21732) which makes binary argument optional (CL 22410) -cmd/trace: now supports visualization of very large traces by splitting them into parts (CL 22731) -cmd/trace: tracing has become significantly faster (CL 21512) - -Ports: - -We now require OpenBSD 5.6+ (CL 18219, crypto/rand using getentropy) -plan9/arm support? Start at least. -cgo and external linking support for linux/mips64 and linux/mips64le (CL 19809, ...) - -New packages: - -* context (and new support in net, net/http, os/exec, net/http/httptrace) -* net/http/httptrace - -API additions and behavior changes: - -crypto/tls: allow renegotiation to be handled by a client (CL 22475) -runtime: support symbolic backtrace of C code in a cgo crash (CL 17761) -runtime: add CallerFrames and Frames (CL 19869) -runtime: add KeepAlive (CL 23102) -testing/quick: now generates nil values (CL 16470) -net/http/httptest: ResponseRecorder supports trailer (CL 20047) (compat impact: issue 14928) -net/url: support query string without values (CL 19931) -net/textproto: permit all valid token chars in CanonicalMIMEHeaderKey input (CL 18725) -go/doc: add Unordered boolean to Example struct (CL 19280) -time: print zero duration as 0s, not 0 (CL 22357) From ba867a86fa28f9edca64b682bc2df66e73967f56 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 02:50:17 -0400 Subject: [PATCH 202/267] api: update next.txt Change-Id: I7b38309d927409a92f68f5d26f491b0166eba838 Reviewed-on: https://go-review.googlesource.com/23378 Reviewed-by: Ian Lance Taylor Run-TryBot: Russ Cox --- api/next.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/api/next.txt b/api/next.txt index 09e6cf1f965cb2..ae60f2d73a41b1 100644 --- a/api/next.txt +++ b/api/next.txt @@ -17,7 +17,15 @@ pkg context, type Context interface, Err() error pkg context, type Context interface, Value(interface{}) interface{} pkg context, var Canceled error pkg context, var DeadlineExceeded error +pkg crypto/tls, const RenegotiateFreelyAsClient = 2 +pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport +pkg crypto/tls, const RenegotiateNever = 0 +pkg crypto/tls, const RenegotiateNever RenegotiationSupport +pkg crypto/tls, const RenegotiateOnceAsClient = 1 +pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool +pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport +pkg crypto/tls, type RenegotiationSupport int pkg crypto/x509, func SystemCertPool() (*CertPool, error) pkg crypto/x509, type SystemRootsError struct, Err error pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error) @@ -147,8 +155,9 @@ pkg debug/elf, const R_390_TLS_TPOFF R_390 pkg debug/elf, method (R_390) GoString() string pkg debug/elf, method (R_390) String() string pkg debug/elf, type R_390 int -pkg encoding/json, method (*Encoder) DisableHTMLEscaping() -pkg encoding/json, method (*Encoder) Indent(string, string) +pkg encoding/json, method (*Encoder) SetEscapeHTML(bool) +pkg encoding/json, method (*Encoder) SetIndent(string, string) +pkg go/build, type Package struct, BinaryOnly bool pkg go/build, type Package struct, CgoFFLAGS []string pkg go/build, type Package struct, FFiles []string pkg go/doc, type Example struct, Unordered bool @@ -164,16 +173,51 @@ pkg io, type SizedReaderAt interface, Size() int64 pkg math/big, method (*Float) GobDecode([]uint8) error pkg math/big, method (*Float) GobEncode() ([]uint8, error) pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error) -pkg net, type IPNet struct, Zone string pkg net/http, method (*Request) Context() context.Context pkg net/http, method (*Request) WithContext(context.Context) *Request +pkg net/http, type Request struct, Response *Response +pkg net/http, type Response struct, Uncompressed bool pkg net/http, type Transport struct, Dialer *net.Dialer +pkg net/http, type Transport struct, IdleConnTimeout time.Duration +pkg net/http, type Transport struct, MaxIdleConns int pkg net/http, type Transport struct, MaxResponseHeaderBytes int64 +pkg net/http, var ErrUseLastResponse error +pkg net/http, var LocalAddrContextKey *contextKey pkg net/http, var ServerContextKey *contextKey pkg net/http/cgi, type Handler struct, Stderr io.Writer pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request -pkg net/http/httptest, method (*ResponseRecorder) Trailers() http.Header +pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response +pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace +pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context +pkg net/http/httptrace, type ClientTrace struct +pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error) +pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string) +pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo) +pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo) +pkg net/http/httptrace, type ClientTrace struct, GetConn func(string) +pkg net/http/httptrace, type ClientTrace struct, Got100Continue func() +pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo) +pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func() +pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error) +pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func() +pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func() +pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo) +pkg net/http/httptrace, type DNSDoneInfo struct +pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr +pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool +pkg net/http/httptrace, type DNSDoneInfo struct, Err error +pkg net/http/httptrace, type DNSStartInfo struct +pkg net/http/httptrace, type DNSStartInfo struct, Host string +pkg net/http/httptrace, type GotConnInfo struct +pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn +pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration +pkg net/http/httptrace, type GotConnInfo struct, Reused bool +pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool +pkg net/http/httptrace, type WroteRequestInfo struct +pkg net/http/httptrace, type WroteRequestInfo struct, Err error pkg net/url, type URL struct, ForceQuery bool +pkg os, method (*File) Size() (int64, error) +pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd pkg os/user, func LookupGroup(string) (*Group, error) pkg os/user, func LookupGroupId(string) (*Group, error) pkg os/user, method (*User) GroupIds() ([]string, error) @@ -187,6 +231,7 @@ pkg os/user, type UnknownGroupIdError string pkg reflect, func StructOf([]StructField) Type pkg reflect, method (StructTag) Lookup(string) (string, bool) pkg runtime, func CallersFrames([]uintptr) *Frames +pkg runtime, func KeepAlive(interface{}) pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) pkg runtime, method (*Frames) Next() (Frame, bool) pkg runtime, type Frame struct @@ -198,6 +243,12 @@ pkg runtime, type Frame struct, Line int pkg runtime, type Frame struct, PC uintptr pkg runtime, type Frames struct pkg strings, method (*Reader) Reset(string) +pkg syscall (linux-386), type SysProcAttr struct, Unshare uintptr +pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshare uintptr +pkg syscall (linux-amd64), type SysProcAttr struct, Unshare uintptr +pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshare uintptr +pkg syscall (linux-arm), type SysProcAttr struct, Unshare uintptr +pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshare uintptr pkg testing, method (*B) Run(string, func(*B)) bool pkg testing, method (*T) Run(string, func(*T)) bool pkg testing, type InternalExample struct, Unordered bool From 524956f8b976be2b7be829a2d0d87c2951932ac6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 24 May 2016 09:42:33 -0400 Subject: [PATCH 203/267] io: remove SizedReaderAt It's not clear we want to enshrine an io interface in which Size cannot return an error. Because this requires more thought before committing to the API, remove from Go 1.7. Fixes #15818. Change-Id: Ic4138ffb0e033030145a12d33f78078350a8381f Reviewed-on: https://go-review.googlesource.com/23392 Reviewed-by: Austin Clements Run-TryBot: Russ Cox --- api/next.txt | 3 --- src/io/io.go | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/api/next.txt b/api/next.txt index ae60f2d73a41b1..5ae56c126ada20 100644 --- a/api/next.txt +++ b/api/next.txt @@ -167,9 +167,6 @@ pkg io, const SeekEnd = 2 pkg io, const SeekEnd ideal-int pkg io, const SeekStart = 0 pkg io, const SeekStart ideal-int -pkg io, type SizedReaderAt interface { ReadAt, Size } -pkg io, type SizedReaderAt interface, ReadAt([]uint8, int64) (int, error) -pkg io, type SizedReaderAt interface, Size() int64 pkg math/big, method (*Float) GobDecode([]uint8) error pkg math/big, method (*Float) GobEncode() ([]uint8, error) pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error) diff --git a/src/io/io.go b/src/io/io.go index 3d0a5a485e69b7..80398b39973918 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -274,16 +274,6 @@ type RuneScanner interface { UnreadRune() error } -// SizedReaderAt is the interface that groups the basic ReadAt method -// with a Size method that reports the total size of the underlying -// object. It represents a fixed-size data source that supports random -// access by multiple concurrent goroutines. -type SizedReaderAt interface { - ReaderAt - // Size reports the length of the data source in bytes. - Size() int64 -} - // stringWriter is the interface that wraps the WriteString method. type stringWriter interface { WriteString(s string) (n int, err error) From dcc42c7d11ad06bebc9d13d1e812629f930f14a7 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Tue, 24 May 2016 13:53:44 +0300 Subject: [PATCH 204/267] cmd/vet: do not check print-like functions with unknown type Fixes #15787 Change-Id: I559ba886527b474dbdd44fe884c78973b3012377 Reviewed-on: https://go-review.googlesource.com/23351 Run-TryBot: Rob Pike Reviewed-by: Rob Pike --- src/cmd/vet/print.go | 34 ++++++++++++++++++---------------- src/cmd/vet/testdata/print.go | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 07499e6ae6bc6a..f4b985cfbdc461 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -587,22 +587,24 @@ func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, s func (f *File) checkPrint(call *ast.CallExpr, name string) { firstArg := 0 typ := f.pkg.types[call.Fun].Type - if typ != nil { - if sig, ok := typ.(*types.Signature); ok { - if !sig.Variadic() { - // Skip checking non-variadic functions. - return - } - params := sig.Params() - firstArg = params.Len() - 1 - - typ := params.At(firstArg).Type() - typ = typ.(*types.Slice).Elem() - it, ok := typ.(*types.Interface) - if !ok || !it.Empty() { - // Skip variadic functions accepting non-interface{} args. - return - } + if typ == nil { + // Skip checking functions with unknown type. + return + } + if sig, ok := typ.(*types.Signature); ok { + if !sig.Variadic() { + // Skip checking non-variadic functions. + return + } + params := sig.Params() + firstArg = params.Len() - 1 + + typ := params.At(firstArg).Type() + typ = typ.(*types.Slice).Elem() + it, ok := typ.(*types.Interface) + if !ok || !it.Empty() { + // Skip variadic functions accepting non-interface{} args. + return } } args := call.Args diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 261ee788c7b0d0..ab97256c088298 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -8,6 +8,7 @@ package testdata import ( "fmt" + "io" "math" "os" "unsafe" // just for test case printing unsafe.Pointer @@ -272,11 +273,21 @@ func Printf(format string, args ...interface{}) { panic("don't call - testing only") } +// Println is used by the test so we must declare it. +func Println(args ...interface{}) { + panic("don't call - testing only") +} + // Logf is used by the test so we must declare it. func Logf(format string, args ...interface{}) { panic("don't call - testing only") } +// Log is used by the test so we must declare it. +func Log(args ...interface{}) { + panic("don't call - testing only") +} + // printf is used by the test so we must declare it. func printf(format string, args ...interface{}) { panic("don't call - testing only") @@ -415,3 +426,10 @@ var recursiveStruct1V = &RecursiveStruct1{} func (int) String() { return "" } + +func (s *unknownStruct) Fprintln(w io.Writer, s string) {} + +func UnknownStructFprintln() { + s := unknownStruct{} + s.Fprintln(os.Stdout, "hello, world!") // OK +} From 7b9d3ff4cbd93c0b9e69c78cbb2cb891839c7fb3 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Sat, 21 May 2016 14:37:29 +0200 Subject: [PATCH 205/267] testing: don't be silent if a test's goroutine fails a test after test exits Fixes #15654 Change-Id: I9bdaa9b76d480d75f24d95f0235efd4a79e3593e Reviewed-on: https://go-review.googlesource.com/23320 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot Reviewed-by: Joe Tsai --- src/testing/sub_test.go | 21 +++++++++++++++++++++ src/testing/testing.go | 12 ++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go index 2804550737429b..2a24aaacfd72a0 100644 --- a/src/testing/sub_test.go +++ b/src/testing/sub_test.go @@ -307,6 +307,27 @@ func TestTRun(t *T) { f: func(t *T) { t.Skip() }, + }, { + desc: "panic on goroutine fail after test exit", + ok: false, + maxPar: 4, + f: func(t *T) { + ch := make(chan bool) + t.Run("", func(t *T) { + go func() { + <-ch + defer func() { + if r := recover(); r == nil { + realTest.Errorf("expected panic") + } + ch <- true + }() + t.Errorf("failed after success") + }() + }) + ch <- true + <-ch + }, }} for _, tc := range testCases { ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", "")) diff --git a/src/testing/testing.go b/src/testing/testing.go index 3a7a135a3c6842..9943fa6b4d8c21 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -196,13 +196,14 @@ var ( // common holds the elements common between T and B and // captures common methods such as Errorf. type common struct { - mu sync.RWMutex // guards output and failed + mu sync.RWMutex // guards output, failed, and done. output []byte // Output generated by test or benchmark. w io.Writer // For flushToParent. chatty bool // A copy of the chatty flag. failed bool // Test or benchmark has failed. skipped bool // Test of benchmark has been skipped. - finished bool + finished bool // Test function has completed. + done bool // Test is finished and all subtests have completed. parent *common level int // Nesting depth of test or benchmark. @@ -351,6 +352,10 @@ func (c *common) Fail() { } c.mu.Lock() defer c.mu.Unlock() + // c.done needs to be locked to synchronize checks to c.done in parent tests. + if c.done { + panic("Fail in goroutine after " + c.name + " has completed") + } c.failed = true } @@ -540,6 +545,9 @@ func tRunner(t *T, fn func(t *T)) { } t.report() // Report after all subtests have finished. + // Do not lock t.done to allow race detector to detect race in case + // the user does not appropriately synchronizes a goroutine. + t.done = true t.signal <- true }() From a0abecf1020c33e82c464f7891b317e83f0c6a78 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 24 May 2016 13:40:02 -0400 Subject: [PATCH 206/267] cmd/link: ensure -fuse-ld=gold uses gold Fixes #15696 Change-Id: I134e918dc56f79a72a04aa54f415371884113d2a Reviewed-on: https://go-review.googlesource.com/23400 Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/lib.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 4fff35c38e0633..3860287e676033 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1137,6 +1137,16 @@ func hostlink() { // // In both cases, switch to gold. argv = append(argv, "-fuse-ld=gold") + + // If gold is not installed, gcc will silently switch + // back to ld.bfd. So we parse the version information + // and provide a useful error if gold is missing. + cmd := exec.Command(extld, "-fuse-ld=gold", "-Wl,--version") + if out, err := cmd.CombinedOutput(); err != nil { + if !bytes.Contains(out, []byte("GNU gold")) { + log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out) + } + } } } From 2f9eeea212681927385a4713004438cd864966e0 Mon Sep 17 00:00:00 2001 From: "Jeff R. Allen" Date: Tue, 24 May 2016 23:46:11 +0600 Subject: [PATCH 207/267] cmd/go: document testdata directory in "go help test" Document the correct use of the testdata directory where test writers might be expecting to find it. It seems that alldocs.go was out of date, so it has picked up some other changes with this commit. Fixes #14715. Change-Id: I0a22676bb7a64b2a61b56495f7ea38db889d8b37 Reviewed-on: https://go-review.googlesource.com/23353 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/go/alldocs.go | 16 ++++++++++++++-- src/cmd/go/test.go | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 2b74cb59e35c58..2a64657732067c 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -570,6 +570,8 @@ syntax of package template. The default output is equivalent to -f Stale bool // would 'go install' do anything for this package? StaleReason string // explanation for Stale==true Root string // Go root or Go path dir containing this package + ConflictDir string // this directory shadows Dir in $GOPATH + BinaryOnly bool // binary-only package: cannot be recompiled from sources // Source files GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -704,6 +706,9 @@ Each listed package causes the execution of a separate test binary. Test files that declare a package with the suffix "_test" will be compiled as a separate package, and then linked and run with the main test binary. +The go tool will ignore a directory named "testdata", making it available +to hold ancillary data needed by the tests. + By default, go test needs no arguments. It compiles and tests the package with source in the current directory, including tests, and runs the tests. @@ -882,7 +887,15 @@ the extension of the file name. These extensions are: Files of each of these types except .syso may contain build constraints, but the go command stops scanning for build constraints at the first item in the file that is not a blank line or //-style -line comment. +line comment. See the go/build package documentation for +more details. + +Non-test Go source files can also include a //go:binary-only-package +comment, indicating that the package sources are included +for documentation only and must not be used to build the +package binary. This enables distribution of Go packages in +their compiled form alone. See the go/build package documentation +for more details. GOPATH environment variable @@ -1457,7 +1470,6 @@ control the execution of any test: -trace trace.out Write an execution trace to the specified file before exiting. - Writes test binary as -c would. -v Verbose output: log all tests as they are run. Also print all diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 02abcbe23a07f0..bc5982e61ce9cf 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -59,6 +59,9 @@ Each listed package causes the execution of a separate test binary. Test files that declare a package with the suffix "_test" will be compiled as a separate package, and then linked and run with the main test binary. +The go tool will ignore a directory named "testdata", making it available +to hold ancillary data needed by the tests. + By default, go test needs no arguments. It compiles and tests the package with source in the current directory, including tests, and runs the tests. From 3474610fbc81f7e9f3f2cb23dc1554b3f5cec657 Mon Sep 17 00:00:00 2001 From: "Jeff R. Allen" Date: Tue, 24 May 2016 23:00:06 +0600 Subject: [PATCH 208/267] math/rand: Doc fix for how many bits Seed uses Document the fact that the default Source uses only the bottom 31 bits of the given seed. Fixes #15788 Change-Id: If20d1ec44a55c793a4a0a388f84b9392c2102bd1 Reviewed-on: https://go-review.googlesource.com/23352 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/math/rand/rand.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go index d693bfb52f243c..add039ed4bdade 100644 --- a/src/math/rand/rand.go +++ b/src/math/rand/rand.go @@ -179,7 +179,8 @@ var globalRand = New(&lockedSource{src: NewSource(1)}) // Seed uses the provided seed value to initialize the default Source to a // deterministic state. If Seed is not called, the generator behaves as -// if seeded by Seed(1). +// if seeded by Seed(1). Only uses the bottom 31 bits of seed; the top 33 +// bits are ignored. func Seed(seed int64) { globalRand.Seed(seed) } // Int63 returns a non-negative pseudo-random 63-bit integer as an int64 From 7b6b5e340403c32756a92294729dc52f308b841a Mon Sep 17 00:00:00 2001 From: "Jeff R. Allen" Date: Wed, 25 May 2016 00:12:22 +0600 Subject: [PATCH 209/267] doc: add notes on good commit messages Explain Brad's algorithm for generating commit headlines. Fixes #15700 Change-Id: Ic602f17629b3dd7675e2bb1ed119062c03353ee9 Reviewed-on: https://go-review.googlesource.com/23355 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- doc/contribute.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/contribute.html b/doc/contribute.html index 1cd6f37d34e950..bcf7b25c511580 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -353,10 +353,13 @@

Make a change

The first line of the change description is conventionally a one-line summary of the change, prefixed by the primary affected package, and is used as the subject for code review mail. -The rest of the -description elaborates and should provide context for the +It should complete the sentence "This change modifies Go to _____." +The rest of the description elaborates and should provide context for the change and explain what it does. +Write in complete sentences with correct punctuation, just like +for your comments in Go. If there is a helpful reference, mention it here. +If you've fixed an issue, reference it by number with a # before it.

@@ -364,7 +367,7 @@

Make a change

-math: improved Sin, Cos and Tan precision for very large arguments
+math: improve Sin, Cos and Tan precision for very large arguments
 
 The existing implementation has poor numerical properties for
 large arguments, so use the McGillicutty algorithm to improve

From a640d95172ec516a3b727a8ca796c64f5aea89ec Mon Sep 17 00:00:00 2001
From: Austin Clements 
Date: Fri, 20 May 2016 14:57:55 -0400
Subject: [PATCH 210/267] runtime: update SP when jumping stacks in traceback

When gentraceback starts on a system stack in sigprof, it is
configured to jump to the user stack when it reaches the end of the
system stack. Currently this updates the current frame's FP, but not
its SP. This is okay on non-LR machines (x86) because frame.sp is only
used to find defers, which the bottom-most frame of the user stack
will never have.

However, on LR machines, we use frame.sp to find the saved LR. We then
use to resolve the function of the next frame, which is used to
resolved the size of the next frame. Since we're not updating frame.sp
on a stack jump, we read the saved LR from the system stack instead of
the user stack and wind up resolving the wrong function and hence the
wrong frame size for the next frame.

This has had remarkably few ill effects (though the resulting profiles
must be wrong). We noticed it because of a bad interaction with stack
barriers. Specifically, once we get the next frame size wrong, we also
get the location of its LR wrong. If we happen to get a stack slot
that contains a stale stack barrier LR (for a stack barrier we already
hit) and hasn't been overwritten with something else as we re-grew the
stack, gentraceback will fail with a "found next stack barrier at ..."
error, pointing at the slot that it thinks is an LR, but isn't.

Fixes #15138.

Updates #15313 (might fix it).

Change-Id: I13cfa322b44c0c2f23ac2b3d03e12631e4a6406b
Reviewed-on: https://go-review.googlesource.com/23291
Run-TryBot: Austin Clements 
TryBot-Result: Gobot Gobot 
Reviewed-by: Rick Hudson 
Reviewed-by: Cherry Zhang 
---
 src/runtime/traceback.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index eef34708031a66..279fb52fc0c4e3 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -256,6 +256,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			sp := frame.sp
 			if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
 				sp = gp.m.curg.sched.sp
+				frame.sp = sp
 				stkbarG = gp.m.curg
 				stkbar = stkbarG.stkbar[stkbarG.stkbarPos:]
 				cgoCtxt = gp.m.curg.cgoCtxt

From 93e8e704996ce100fe46b2249324442947e47a9d Mon Sep 17 00:00:00 2001
From: Robert Griesemer 
Date: Tue, 24 May 2016 14:12:35 -0700
Subject: [PATCH 211/267] all: fixed a handful of typos

Change-Id: Ib0683f27b44e2f107cca7a8dcc01d230cbcd5700
Reviewed-on: https://go-review.googlesource.com/23404
Reviewed-by: Alan Donovan 
---
 doc/install-source.html         | 6 +++---
 src/container/list/list_test.go | 2 +-
 src/encoding/csv/reader.go      | 2 +-
 src/runtime/mgc.go              | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/doc/install-source.html b/doc/install-source.html
index 9a817676c17bd9..1d7df3d42c9b62 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -63,19 +63,19 @@ 

Introduction

arm64 (AArch64)
- Supports Linux and Darwin binaries. New in 1.5 and not as well excercised as other ports. + Supports Linux and Darwin binaries. New in 1.5 and not as well exercised as other ports.
ppc64, ppc64le (64-bit PowerPC big- and little-endian)
- Supports Linux binaries. New in 1.5 and not as well excercised as other ports. + Supports Linux binaries. New in 1.5 and not as well exercised as other ports.
mips64, mips64le (64-bit MIPS big- and little-endian)
- Supports Linux binaries. New in 1.6 and not as well excercised as other ports. + Supports Linux binaries. New in 1.6 and not as well exercised as other ports.
diff --git a/src/container/list/list_test.go b/src/container/list/list_test.go index 4d8bfc2bf0791b..e3bfe53a4981fa 100644 --- a/src/container/list/list_test.go +++ b/src/container/list/list_test.go @@ -326,7 +326,7 @@ func TestInsertAfterUnknownMark(t *testing.T) { } // Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l. -func TestMoveUnkownMark(t *testing.T) { +func TestMoveUnknownMark(t *testing.T) { var l1 List e1 := l1.PushBack(1) diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go index 58f6eed1e66c3f..5d5e3e5bf7cee1 100644 --- a/src/encoding/csv/reader.go +++ b/src/encoding/csv/reader.go @@ -234,7 +234,7 @@ func (r *Reader) parseRecord() (fields []string, err error) { for { haveField, delim, err := r.parseField() if haveField { - // If FieldsPerRecord is greater then 0 we can assume the final + // If FieldsPerRecord is greater than 0 we can assume the final // length of fields to be equal to FieldsPerRecord. if r.FieldsPerRecord > 0 && fields == nil { fields = make([]string, 0, r.FieldsPerRecord) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 3d4df104cbae0b..1eabf43d6f24c1 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1388,7 +1388,7 @@ func gcBgMarkWorker(_p_ *p) { notewakeup(&work.bgMarkReady) for { - // Go to sleep until woken by gcContoller.findRunnable. + // Go to sleep until woken by gcController.findRunnable. // We can't releasem yet since even the call to gopark // may be preempted. gopark(func(g *g, parkp unsafe.Pointer) bool { From fa3f484800415662cc741bbb8968ebb72896e20a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 24 May 2016 11:39:48 -0700 Subject: [PATCH 212/267] encoding/csv: clarify that this package supports RFC 4180 The intent of this comment is to reduce the number of issues opened against the package to add support for new kinds of CSV formats, such as issues #3150, #8458, #12372, #12755. Change-Id: I452c0b748e4ca9ebde3e6cea188bf7774372148e Reviewed-on: https://go-review.googlesource.com/23401 Reviewed-by: Andrew Gerrand --- src/encoding/csv/reader.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go index 5d5e3e5bf7cee1..89283bb3031d4a 100644 --- a/src/encoding/csv/reader.go +++ b/src/encoding/csv/reader.go @@ -3,6 +3,8 @@ // license that can be found in the LICENSE file. // Package csv reads and writes comma-separated values (CSV) files. +// There are many kinds of CSV files; this package supports the format +// described in RFC 4180. // // A csv file contains zero or more records of one or more fields per record. // Each record is separated by the newline character. The final record may From 72eb46c5a086051e3677579a0810922724eb6a6d Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 16 May 2016 15:51:07 +0200 Subject: [PATCH 213/267] runtime,runtime/cgo: save callee-saved FP register on arm Other GOARCHs already handle their callee-saved FP registers, but arm was missing. Without this change, code using Cgo and floating point code might fail in mysterious and hard to debug ways. There are no floating point registers when GOARM=5, so skip the registers when runtime.goarm < 6. darwin/arm doesn't support GOARM=5, so the check is left out of rt0_darwin_arm.s. Fixes #14876 Change-Id: I6bcb90a76df3664d8ba1f33123a74b1eb2c9f8b2 Reviewed-on: https://go-review.googlesource.com/23140 Run-TryBot: Elias Naur TryBot-Result: Gobot Gobot Reviewed-by: Minux Ma --- src/runtime/cgo/asm_arm.s | 34 +++++++++++++++++++++++++++++++++- src/runtime/rt0_darwin_arm.s | 19 ++++++++++++++++++- src/runtime/rt0_linux_arm.s | 27 ++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s index 08472b6ab76ad9..0f354220bbf0b7 100644 --- a/src/runtime/cgo/asm_arm.s +++ b/src/runtime/cgo/asm_arm.s @@ -16,8 +16,40 @@ TEXT crosscall2(SB),NOSPLIT,$-4 * Additionally, runtime·load_g will clobber R0, so we need to save R0 * nevertheless. */ + SUB $(8*9), R13 // Reserve space for the floating point registers. MOVM.WP [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13) + + // Skip floating point registers on GOARM < 6. + MOVB runtime·goarm(SB), R11 + CMP $6, R11 + BLT skipfpsave + MOVD F8, (14*4+8*1)(R13) + MOVD F9, (14*4+8*2)(R13) + MOVD F10, (14*4+8*3)(R13) + MOVD F11, (14*4+8*4)(R13) + MOVD F12, (14*4+8*5)(R13) + MOVD F13, (14*4+8*6)(R13) + MOVD F14, (14*4+8*7)(R13) + MOVD F15, (14*4+8*8)(R13) + +skipfpsave: BL runtime·load_g(SB) MOVW R15, R14 // R15 is PC. MOVW 0(R13), R15 - MOVM.IAW (R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R15] + + MOVB runtime·goarm(SB), R11 + CMP $6, R11 + BLT skipfprest + MOVD (14*4+8*1)(R13), F8 + MOVD (14*4+8*2)(R13), F9 + MOVD (14*4+8*3)(R13), F10 + MOVD (14*4+8*4)(R13), F11 + MOVD (14*4+8*5)(R13), F12 + MOVD (14*4+8*6)(R13), F13 + MOVD (14*4+8*7)(R13), F14 + MOVD (14*4+8*8)(R13), F15 + +skipfprest: + MOVM.IAW (R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14] + ADD $(8*9), R13 + MOVW R14, R15 diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s index 59733d3ff60fe0..526d88f13d2430 100644 --- a/src/runtime/rt0_darwin_arm.s +++ b/src/runtime/rt0_darwin_arm.s @@ -16,7 +16,7 @@ TEXT _rt0_arm_darwin(SB),7,$-4 // // Note that all currently shipping darwin/arm platforms require // cgo and do not support c-shared. -TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$32 +TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$104 // Preserve callee-save registers. MOVW R4, 12(R13) MOVW R5, 16(R13) @@ -25,6 +25,15 @@ TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$32 MOVW R8, 28(R13) MOVW R11, 32(R13) + MOVD F8, (32+8*1)(R13) + MOVD F9, (32+8*2)(R13) + MOVD F10, (32+8*3)(R13) + MOVD F11, (32+8*4)(R13) + MOVD F12, (32+8*5)(R13) + MOVD F13, (32+8*6)(R13) + MOVD F14, (32+8*7)(R13) + MOVD F15, (32+8*8)(R13) + MOVW R0, _rt0_arm_darwin_lib_argc<>(SB) MOVW R1, _rt0_arm_darwin_lib_argv<>(SB) @@ -57,6 +66,14 @@ rr: MOVW 24(R13), R7 MOVW 28(R13), R8 MOVW 32(R13), R11 + MOVD (32+8*1)(R13), F8 + MOVD (32+8*2)(R13), F9 + MOVD (32+8*3)(R13), F10 + MOVD (32+8*4)(R13), F11 + MOVD (32+8*5)(R13), F12 + MOVD (32+8*6)(R13), F13 + MOVD (32+8*7)(R13), F14 + MOVD (32+8*8)(R13), F15 RET diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s index a4419b898e31ef..597e642adb7177 100644 --- a/src/runtime/rt0_linux_arm.s +++ b/src/runtime/rt0_linux_arm.s @@ -12,7 +12,7 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4 // When building with -buildmode=c-shared, this symbol is called when the shared // library is loaded. -TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32 +TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$104 // Preserve callee-save registers. Raspberry Pi's dlopen(), for example, // actually cares that R11 is preserved. MOVW R4, 12(R13) @@ -22,6 +22,19 @@ TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32 MOVW R8, 28(R13) MOVW R11, 32(R13) + // Skip floating point registers on GOARM < 6. + MOVB runtime·goarm(SB), R11 + CMP $6, R11 + BLT skipfpsave + MOVD F8, (32+8*1)(R13) + MOVD F9, (32+8*2)(R13) + MOVD F10, (32+8*3)(R13) + MOVD F11, (32+8*4)(R13) + MOVD F12, (32+8*5)(R13) + MOVD F13, (32+8*6)(R13) + MOVD F14, (32+8*7)(R13) + MOVD F15, (32+8*8)(R13) +skipfpsave: // Save argc/argv. MOVW R0, _rt0_arm_linux_lib_argc<>(SB) MOVW R1, _rt0_arm_linux_lib_argv<>(SB) @@ -46,6 +59,18 @@ nocgo: BL runtime·newosproc0(SB) rr: // Restore callee-save registers and return. + MOVB runtime·goarm(SB), R11 + CMP $6, R11 + BLT skipfprest + MOVD (32+8*1)(R13), F8 + MOVD (32+8*2)(R13), F9 + MOVD (32+8*3)(R13), F10 + MOVD (32+8*4)(R13), F11 + MOVD (32+8*5)(R13), F12 + MOVD (32+8*6)(R13), F13 + MOVD (32+8*7)(R13), F14 + MOVD (32+8*8)(R13), F15 +skipfprest: MOVW 12(R13), R4 MOVW 16(R13), R5 MOVW 20(R13), R6 From f2f3b6cd8fbe9f823fd6946f055bb70c3ef6f9db Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 25 May 2016 13:24:36 +0200 Subject: [PATCH 214/267] cmd/link: fix ARM gold linker check CL 23400 introduced a check to make sure the gold linker is used on ARM host links. The check itself works, but the error checking logic was reversed; fix it. I manually verified that the check now correctly rejects host links on my RPi2 running an ancient rasbian without the gold linker installed. Updates #15696 Change-Id: I927832620f0a60e91a71fdedf8cbd2550247b666 Reviewed-on: https://go-review.googlesource.com/23421 Run-TryBot: Elias Naur Reviewed-by: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/lib.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 3860287e676033..da00de8547c748 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1142,7 +1142,7 @@ func hostlink() { // back to ld.bfd. So we parse the version information // and provide a useful error if gold is missing. cmd := exec.Command(extld, "-fuse-ld=gold", "-Wl,--version") - if out, err := cmd.CombinedOutput(); err != nil { + if out, err := cmd.CombinedOutput(); err == nil { if !bytes.Contains(out, []byte("GNU gold")) { log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out) } From 9f38796270a017de8d9e1f102b28576826e6a188 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 24 May 2016 19:04:51 -0400 Subject: [PATCH 215/267] reflect: remove type info for unexported methods Also remove some of the now unnecessary corner case handling and tests I've been adding recently for unexported method data. For #15673 Change-Id: Ie0c7b03f2370bbe8508cdc5be765028f08000bd7 Reviewed-on: https://go-review.googlesource.com/23410 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/reflect/all_test.go | 84 ++--------------------------------------- src/reflect/type.go | 29 +++++--------- 2 files changed, 13 insertions(+), 100 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index f09ffeb56615c5..c801bfc1ec559f 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -1889,32 +1889,6 @@ type Tbigp [2]uintptr func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) } -// Again, with an unexported method. - -type tsmallv byte - -func (v tsmallv) m(x int, b byte) (byte, int) { return b, x + int(v) } - -type tsmallp byte - -func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x + int(*p) } - -type twordv uintptr - -func (v twordv) m(x int, b byte) (byte, int) { return b, x + int(v) } - -type twordp uintptr - -func (p *twordp) m(x int, b byte) (byte, int) { return b, x + int(*p) } - -type tbigv [2]uintptr - -func (v tbigv) m(x int, b byte) (byte, int) { return b, x + int(v[0]) + int(v[1]) } - -type tbigp [2]uintptr - -func (p *tbigp) m(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) } - type tinter interface { m(int, byte) (byte, int) } @@ -1958,7 +1932,6 @@ func TestMethod5(t *testing.T) { } var TinterType = TypeOf(new(Tinter)).Elem() - var tinterType = TypeOf(new(tinter)).Elem() CheckI := func(name string, i interface{}, inc int) { v := ValueOf(i) @@ -2000,39 +1973,6 @@ func TestMethod5(t *testing.T) { CheckI("t1", t1, 40) CheckI("&t1", &t1, 40) - methodShouldPanic := func(name string, i interface{}) { - v := ValueOf(i) - m := v.Method(0) - shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) }) - shouldPanic(func() { m.Interface() }) - - v = v.Convert(tinterType) - m = v.Method(0) - shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) }) - shouldPanic(func() { m.Interface() }) - } - - _sv := tsmallv(1) - methodShouldPanic("_sv", _sv) - methodShouldPanic("&_sv", &_sv) - - _sp := tsmallp(2) - methodShouldPanic("&_sp", &_sp) - - _wv := twordv(3) - methodShouldPanic("_wv", _wv) - methodShouldPanic("&_wv", &_wv) - - _wp := twordp(4) - methodShouldPanic("&_wp", &_wp) - - _bv := tbigv([2]uintptr{5, 6}) - methodShouldPanic("_bv", _bv) - methodShouldPanic("&_bv", &_bv) - - _bp := tbigp([2]uintptr{7, 8}) - methodShouldPanic("&_bp", &_bp) - var tnil Tinter vnil := ValueOf(&tnil).Elem() shouldPanic(func() { vnil.Method(0) }) @@ -2416,14 +2356,8 @@ var unexpi unexpI = new(unexp) func TestUnexportedMethods(t *testing.T) { typ := TypeOf(unexpi) - if got := typ.NumMethod(); got != 1 { - t.Error("NumMethod=%d, want 1 satisfied method", got) - } - if typ.Method(0).Type == nil { - t.Error("missing type for satisfied method 'f'") - } - if !typ.Method(0).Func.IsValid() { - t.Error("missing func for satisfied method 'f'") + if got := typ.NumMethod(); got != 0 { + t.Errorf("NumMethod=%d, want 0 satisfied methods", got) } } @@ -2915,12 +2849,11 @@ func TestUnexported(t *testing.T) { isValid(v.Elem().Field(1)) isValid(v.Elem().FieldByName("x")) isValid(v.Elem().FieldByName("y")) - isValid(v.Type().Method(0).Func) shouldPanic(func() { v.Elem().Field(0).Interface() }) shouldPanic(func() { v.Elem().Field(1).Interface() }) shouldPanic(func() { v.Elem().FieldByName("x").Interface() }) shouldPanic(func() { v.Elem().FieldByName("y").Interface() }) - shouldPanic(func() { v.Type().Method(0).Func.Interface() }) + shouldPanic(func() { v.Type().Method(0) }) } func TestSetPanic(t *testing.T) { @@ -5769,17 +5702,6 @@ func TestNameBytesAreAligned(t *testing.T) { } } -func TestMethodPkgPathReadable(t *testing.T) { - // Reading the Method type for an unexported method triggers an - // offset resolution via p.name.pkgPath(). Make sure it uses a - // valid base pointer for the offset. - v := ValueOf(embed{}) - m := v.Type().Method(0) - if m.PkgPath != "reflect" { - t.Errorf(`PkgPath=%q, want "reflect"`, m.PkgPath) - } -} - func TestTypeStrings(t *testing.T) { type stringTest struct { typ Type diff --git a/src/reflect/type.go b/src/reflect/type.go index c9389199d8b963..1dff74df62a06f 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -768,10 +768,7 @@ var methodCache struct { m map[*rtype][]method } -// satisfiedMethods returns methods of t that satisfy an interface. -// This may include unexported methods that satisfy an interface -// defined with unexported methods in the same package as t. -func (t *rtype) satisfiedMethods() []method { +func (t *rtype) exportedMethods() []method { methodCache.RLock() methods, found := methodCache.m[t] methodCache.RUnlock() @@ -785,19 +782,21 @@ func (t *rtype) satisfiedMethods() []method { return nil } allm := ut.methods() - allSatisfied := true + allExported := true for _, m := range allm { - if m.mtyp == 0 { - allSatisfied = false + name := t.nameOff(m.name) + if !name.isExported() { + allExported = false break } } - if allSatisfied { + if allExported { methods = allm } else { methods = make([]method, 0, len(allm)) for _, m := range allm { - if m.mtyp != 0 { + name := t.nameOff(m.name) + if name.isExported() { methods = append(methods, m) } } @@ -819,7 +818,7 @@ func (t *rtype) NumMethod() int { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.NumMethod() } - return len(t.satisfiedMethods()) + return len(t.exportedMethods()) } func (t *rtype) Method(i int) (m Method) { @@ -827,7 +826,7 @@ func (t *rtype) Method(i int) (m Method) { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.Method(i) } - methods := t.satisfiedMethods() + methods := t.exportedMethods() if i < 0 || i >= len(methods) { panic("reflect: Method index out of range") } @@ -835,14 +834,6 @@ func (t *rtype) Method(i int) (m Method) { pname := t.nameOff(p.name) m.Name = pname.name() fl := flag(Func) - if !pname.isExported() { - m.PkgPath = pname.pkgPath() - if m.PkgPath == "" { - ut := t.uncommon() - m.PkgPath = t.nameOff(ut.pkgPath).name() - } - fl |= flagStickyRO - } mtyp := t.typeOff(p.mtyp) ft := (*funcType)(unsafe.Pointer(mtyp)) in := make([]Type, 0, 1+len(ft.in())) From 786e51d7baf6535290ecb0f34c9e73d7dcc21b02 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 24 May 2016 16:53:48 -0700 Subject: [PATCH 216/267] cmd/compile: add generated tests for constant folding Covers a bunch of constant-folding rules in generic.rules that aren't being covered currently. Increases coverage in generic.rules from 65% to 72%. Change-Id: I7bf58809faf22e97070183b42e6dd7d3f35bf5f9 Reviewed-on: https://go-review.googlesource.com/23407 Run-TryBot: Todd Neal TryBot-Result: Gobot Gobot Reviewed-by: Todd Neal --- src/cmd/compile/internal/gc/constFold_test.go | 12416 ++++++++++++++++ .../internal/gc/testdata/gen/constFoldGen.go | 224 + 2 files changed, 12640 insertions(+) create mode 100644 src/cmd/compile/internal/gc/constFold_test.go create mode 100644 src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go new file mode 100644 index 00000000000000..118183dd2fa68e --- /dev/null +++ b/src/cmd/compile/internal/gc/constFold_test.go @@ -0,0 +1,12416 @@ +package gc + +import "testing" + +func TestConstFolduint64add(t *testing.T) { + var x, y, r uint64 + x = 0 + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 4294967296 + r = x + y + if r != 4294967296 { + t.Errorf("0 + 4294967296 = %d, want 4294967296", r) + } + y = 18446744073709551615 + r = x + y + if r != 18446744073709551615 { + t.Errorf("0 + 18446744073709551615 = %d, want 18446744073709551615", r) + } + x = 1 + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 4294967296 + r = x + y + if r != 4294967297 { + t.Errorf("1 + 4294967296 = %d, want 4294967297", r) + } + y = 18446744073709551615 + r = x + y + if r != 0 { + t.Errorf("1 + 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x + y + if r != 4294967296 { + t.Errorf("4294967296 + 0 = %d, want 4294967296", r) + } + y = 1 + r = x + y + if r != 4294967297 { + t.Errorf("4294967296 + 1 = %d, want 4294967297", r) + } + y = 4294967296 + r = x + y + if r != 8589934592 { + t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r) + } + y = 18446744073709551615 + r = x + y + if r != 4294967295 { + t.Errorf("4294967296 + 18446744073709551615 = %d, want 4294967295", r) + } + x = 18446744073709551615 + y = 0 + r = x + y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 + 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("18446744073709551615 + 1 = %d, want 0", r) + } + y = 4294967296 + r = x + y + if r != 4294967295 { + t.Errorf("18446744073709551615 + 4294967296 = %d, want 4294967295", r) + } + y = 18446744073709551615 + r = x + y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 + 18446744073709551615 = %d, want 18446744073709551614", r) + } +} +func TestConstFolduint64sub(t *testing.T) { + var x, y, r uint64 + x = 0 + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != 18446744073709551615 { + t.Errorf("0 - 1 = %d, want 18446744073709551615", r) + } + y = 4294967296 + r = x - y + if r != 18446744069414584320 { + t.Errorf("0 - 4294967296 = %d, want 18446744069414584320", r) + } + y = 18446744073709551615 + r = x - y + if r != 1 { + t.Errorf("0 - 18446744073709551615 = %d, want 1", r) + } + x = 1 + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 4294967296 + r = x - y + if r != 18446744069414584321 { + t.Errorf("1 - 4294967296 = %d, want 18446744069414584321", r) + } + y = 18446744073709551615 + r = x - y + if r != 2 { + t.Errorf("1 - 18446744073709551615 = %d, want 2", r) + } + x = 4294967296 + y = 0 + r = x - y + if r != 4294967296 { + t.Errorf("4294967296 - 0 = %d, want 4294967296", r) + } + y = 1 + r = x - y + if r != 4294967295 { + t.Errorf("4294967296 - 1 = %d, want 4294967295", r) + } + y = 4294967296 + r = x - y + if r != 0 { + t.Errorf("4294967296 - 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x - y + if r != 4294967297 { + t.Errorf("4294967296 - 18446744073709551615 = %d, want 4294967297", r) + } + x = 18446744073709551615 + y = 0 + r = x - y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 - 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x - y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 - 1 = %d, want 18446744073709551614", r) + } + y = 4294967296 + r = x - y + if r != 18446744069414584319 { + t.Errorf("18446744073709551615 - 4294967296 = %d, want 18446744069414584319", r) + } + y = 18446744073709551615 + r = x - y + if r != 0 { + t.Errorf("18446744073709551615 - 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint64div(t *testing.T) { + var x, y, r uint64 + x = 0 + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 4294967296 + r = x / y + if r != 0 { + t.Errorf("0 / 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x / y + if r != 0 { + t.Errorf("0 / 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 4294967296 + r = x / y + if r != 0 { + t.Errorf("1 / 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x / y + if r != 0 { + t.Errorf("1 / 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 1 + r = x / y + if r != 4294967296 { + t.Errorf("4294967296 / 1 = %d, want 4294967296", r) + } + y = 4294967296 + r = x / y + if r != 1 { + t.Errorf("4294967296 / 4294967296 = %d, want 1", r) + } + y = 18446744073709551615 + r = x / y + if r != 0 { + t.Errorf("4294967296 / 18446744073709551615 = %d, want 0", r) + } + x = 18446744073709551615 + y = 1 + r = x / y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 / 1 = %d, want 18446744073709551615", r) + } + y = 4294967296 + r = x / y + if r != 4294967295 { + t.Errorf("18446744073709551615 / 4294967296 = %d, want 4294967295", r) + } + y = 18446744073709551615 + r = x / y + if r != 1 { + t.Errorf("18446744073709551615 / 18446744073709551615 = %d, want 1", r) + } +} +func TestConstFolduint64mul(t *testing.T) { + var x, y, r uint64 + x = 0 + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("0 * 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x * y + if r != 0 { + t.Errorf("0 * 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 4294967296 + r = x * y + if r != 4294967296 { + t.Errorf("1 * 4294967296 = %d, want 4294967296", r) + } + y = 18446744073709551615 + r = x * y + if r != 18446744073709551615 { + t.Errorf("1 * 18446744073709551615 = %d, want 18446744073709551615", r) + } + x = 4294967296 + y = 0 + r = x * y + if r != 0 { + t.Errorf("4294967296 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 4294967296 { + t.Errorf("4294967296 * 1 = %d, want 4294967296", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("4294967296 * 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x * y + if r != 18446744069414584320 { + t.Errorf("4294967296 * 18446744073709551615 = %d, want 18446744069414584320", r) + } + x = 18446744073709551615 + y = 0 + r = x * y + if r != 0 { + t.Errorf("18446744073709551615 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 * 1 = %d, want 18446744073709551615", r) + } + y = 4294967296 + r = x * y + if r != 18446744069414584320 { + t.Errorf("18446744073709551615 * 4294967296 = %d, want 18446744069414584320", r) + } + y = 18446744073709551615 + r = x * y + if r != 1 { + t.Errorf("18446744073709551615 * 18446744073709551615 = %d, want 1", r) + } +} +func TestConstFolduint64mod(t *testing.T) { + var x, y, r uint64 + x = 0 + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("0 % 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x % y + if r != 0 { + t.Errorf("0 % 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 1 { + t.Errorf("1 % 4294967296 = %d, want 1", r) + } + y = 18446744073709551615 + r = x % y + if r != 1 { + t.Errorf("1 % 18446744073709551615 = %d, want 1", r) + } + x = 4294967296 + y = 1 + r = x % y + if r != 0 { + t.Errorf("4294967296 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("4294967296 % 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x % y + if r != 4294967296 { + t.Errorf("4294967296 % 18446744073709551615 = %d, want 4294967296", r) + } + x = 18446744073709551615 + y = 1 + r = x % y + if r != 0 { + t.Errorf("18446744073709551615 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 4294967295 { + t.Errorf("18446744073709551615 % 4294967296 = %d, want 4294967295", r) + } + y = 18446744073709551615 + r = x % y + if r != 0 { + t.Errorf("18446744073709551615 % 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint64add(t *testing.T) { + var x, y, r int64 + x = -9223372036854775808 + y = -9223372036854775808 + r = x + y + if r != 0 { + t.Errorf("-9223372036854775808 + -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x + y + if r != 1 { + t.Errorf("-9223372036854775808 + -9223372036854775807 = %d, want 1", r) + } + y = -4294967296 + r = x + y + if r != 9223372032559808512 { + t.Errorf("-9223372036854775808 + -4294967296 = %d, want 9223372032559808512", r) + } + y = -1 + r = x + y + if r != 9223372036854775807 { + t.Errorf("-9223372036854775808 + -1 = %d, want 9223372036854775807", r) + } + y = 0 + r = x + y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 + 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x + y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775808 + 1 = %d, want -9223372036854775807", r) + } + y = 4294967296 + r = x + y + if r != -9223372032559808512 { + t.Errorf("-9223372036854775808 + 4294967296 = %d, want -9223372032559808512", r) + } + y = 9223372036854775806 + r = x + y + if r != -2 { + t.Errorf("-9223372036854775808 + 9223372036854775806 = %d, want -2", r) + } + y = 9223372036854775807 + r = x + y + if r != -1 { + t.Errorf("-9223372036854775808 + 9223372036854775807 = %d, want -1", r) + } + x = -9223372036854775807 + y = -9223372036854775808 + r = x + y + if r != 1 { + t.Errorf("-9223372036854775807 + -9223372036854775808 = %d, want 1", r) + } + y = -9223372036854775807 + r = x + y + if r != 2 { + t.Errorf("-9223372036854775807 + -9223372036854775807 = %d, want 2", r) + } + y = -4294967296 + r = x + y + if r != 9223372032559808513 { + t.Errorf("-9223372036854775807 + -4294967296 = %d, want 9223372032559808513", r) + } + y = -1 + r = x + y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775807 + -1 = %d, want -9223372036854775808", r) + } + y = 0 + r = x + y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 + 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x + y + if r != -9223372036854775806 { + t.Errorf("-9223372036854775807 + 1 = %d, want -9223372036854775806", r) + } + y = 4294967296 + r = x + y + if r != -9223372032559808511 { + t.Errorf("-9223372036854775807 + 4294967296 = %d, want -9223372032559808511", r) + } + y = 9223372036854775806 + r = x + y + if r != -1 { + t.Errorf("-9223372036854775807 + 9223372036854775806 = %d, want -1", r) + } + y = 9223372036854775807 + r = x + y + if r != 0 { + t.Errorf("-9223372036854775807 + 9223372036854775807 = %d, want 0", r) + } + x = -4294967296 + y = -9223372036854775808 + r = x + y + if r != 9223372032559808512 { + t.Errorf("-4294967296 + -9223372036854775808 = %d, want 9223372032559808512", r) + } + y = -9223372036854775807 + r = x + y + if r != 9223372032559808513 { + t.Errorf("-4294967296 + -9223372036854775807 = %d, want 9223372032559808513", r) + } + y = -4294967296 + r = x + y + if r != -8589934592 { + t.Errorf("-4294967296 + -4294967296 = %d, want -8589934592", r) + } + y = -1 + r = x + y + if r != -4294967297 { + t.Errorf("-4294967296 + -1 = %d, want -4294967297", r) + } + y = 0 + r = x + y + if r != -4294967296 { + t.Errorf("-4294967296 + 0 = %d, want -4294967296", r) + } + y = 1 + r = x + y + if r != -4294967295 { + t.Errorf("-4294967296 + 1 = %d, want -4294967295", r) + } + y = 4294967296 + r = x + y + if r != 0 { + t.Errorf("-4294967296 + 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x + y + if r != 9223372032559808510 { + t.Errorf("-4294967296 + 9223372036854775806 = %d, want 9223372032559808510", r) + } + y = 9223372036854775807 + r = x + y + if r != 9223372032559808511 { + t.Errorf("-4294967296 + 9223372036854775807 = %d, want 9223372032559808511", r) + } + x = -1 + y = -9223372036854775808 + r = x + y + if r != 9223372036854775807 { + t.Errorf("-1 + -9223372036854775808 = %d, want 9223372036854775807", r) + } + y = -9223372036854775807 + r = x + y + if r != -9223372036854775808 { + t.Errorf("-1 + -9223372036854775807 = %d, want -9223372036854775808", r) + } + y = -4294967296 + r = x + y + if r != -4294967297 { + t.Errorf("-1 + -4294967296 = %d, want -4294967297", r) + } + y = -1 + r = x + y + if r != -2 { + t.Errorf("-1 + -1 = %d, want -2", r) + } + y = 0 + r = x + y + if r != -1 { + t.Errorf("-1 + 0 = %d, want -1", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("-1 + 1 = %d, want 0", r) + } + y = 4294967296 + r = x + y + if r != 4294967295 { + t.Errorf("-1 + 4294967296 = %d, want 4294967295", r) + } + y = 9223372036854775806 + r = x + y + if r != 9223372036854775805 { + t.Errorf("-1 + 9223372036854775806 = %d, want 9223372036854775805", r) + } + y = 9223372036854775807 + r = x + y + if r != 9223372036854775806 { + t.Errorf("-1 + 9223372036854775807 = %d, want 9223372036854775806", r) + } + x = 0 + y = -9223372036854775808 + r = x + y + if r != -9223372036854775808 { + t.Errorf("0 + -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x + y + if r != -9223372036854775807 { + t.Errorf("0 + -9223372036854775807 = %d, want -9223372036854775807", r) + } + y = -4294967296 + r = x + y + if r != -4294967296 { + t.Errorf("0 + -4294967296 = %d, want -4294967296", r) + } + y = -1 + r = x + y + if r != -1 { + t.Errorf("0 + -1 = %d, want -1", r) + } + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 4294967296 + r = x + y + if r != 4294967296 { + t.Errorf("0 + 4294967296 = %d, want 4294967296", r) + } + y = 9223372036854775806 + r = x + y + if r != 9223372036854775806 { + t.Errorf("0 + 9223372036854775806 = %d, want 9223372036854775806", r) + } + y = 9223372036854775807 + r = x + y + if r != 9223372036854775807 { + t.Errorf("0 + 9223372036854775807 = %d, want 9223372036854775807", r) + } + x = 1 + y = -9223372036854775808 + r = x + y + if r != -9223372036854775807 { + t.Errorf("1 + -9223372036854775808 = %d, want -9223372036854775807", r) + } + y = -9223372036854775807 + r = x + y + if r != -9223372036854775806 { + t.Errorf("1 + -9223372036854775807 = %d, want -9223372036854775806", r) + } + y = -4294967296 + r = x + y + if r != -4294967295 { + t.Errorf("1 + -4294967296 = %d, want -4294967295", r) + } + y = -1 + r = x + y + if r != 0 { + t.Errorf("1 + -1 = %d, want 0", r) + } + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 4294967296 + r = x + y + if r != 4294967297 { + t.Errorf("1 + 4294967296 = %d, want 4294967297", r) + } + y = 9223372036854775806 + r = x + y + if r != 9223372036854775807 { + t.Errorf("1 + 9223372036854775806 = %d, want 9223372036854775807", r) + } + y = 9223372036854775807 + r = x + y + if r != -9223372036854775808 { + t.Errorf("1 + 9223372036854775807 = %d, want -9223372036854775808", r) + } + x = 4294967296 + y = -9223372036854775808 + r = x + y + if r != -9223372032559808512 { + t.Errorf("4294967296 + -9223372036854775808 = %d, want -9223372032559808512", r) + } + y = -9223372036854775807 + r = x + y + if r != -9223372032559808511 { + t.Errorf("4294967296 + -9223372036854775807 = %d, want -9223372032559808511", r) + } + y = -4294967296 + r = x + y + if r != 0 { + t.Errorf("4294967296 + -4294967296 = %d, want 0", r) + } + y = -1 + r = x + y + if r != 4294967295 { + t.Errorf("4294967296 + -1 = %d, want 4294967295", r) + } + y = 0 + r = x + y + if r != 4294967296 { + t.Errorf("4294967296 + 0 = %d, want 4294967296", r) + } + y = 1 + r = x + y + if r != 4294967297 { + t.Errorf("4294967296 + 1 = %d, want 4294967297", r) + } + y = 4294967296 + r = x + y + if r != 8589934592 { + t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r) + } + y = 9223372036854775806 + r = x + y + if r != -9223372032559808514 { + t.Errorf("4294967296 + 9223372036854775806 = %d, want -9223372032559808514", r) + } + y = 9223372036854775807 + r = x + y + if r != -9223372032559808513 { + t.Errorf("4294967296 + 9223372036854775807 = %d, want -9223372032559808513", r) + } + x = 9223372036854775806 + y = -9223372036854775808 + r = x + y + if r != -2 { + t.Errorf("9223372036854775806 + -9223372036854775808 = %d, want -2", r) + } + y = -9223372036854775807 + r = x + y + if r != -1 { + t.Errorf("9223372036854775806 + -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x + y + if r != 9223372032559808510 { + t.Errorf("9223372036854775806 + -4294967296 = %d, want 9223372032559808510", r) + } + y = -1 + r = x + y + if r != 9223372036854775805 { + t.Errorf("9223372036854775806 + -1 = %d, want 9223372036854775805", r) + } + y = 0 + r = x + y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 + 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x + y + if r != 9223372036854775807 { + t.Errorf("9223372036854775806 + 1 = %d, want 9223372036854775807", r) + } + y = 4294967296 + r = x + y + if r != -9223372032559808514 { + t.Errorf("9223372036854775806 + 4294967296 = %d, want -9223372032559808514", r) + } + y = 9223372036854775806 + r = x + y + if r != -4 { + t.Errorf("9223372036854775806 + 9223372036854775806 = %d, want -4", r) + } + y = 9223372036854775807 + r = x + y + if r != -3 { + t.Errorf("9223372036854775806 + 9223372036854775807 = %d, want -3", r) + } + x = 9223372036854775807 + y = -9223372036854775808 + r = x + y + if r != -1 { + t.Errorf("9223372036854775807 + -9223372036854775808 = %d, want -1", r) + } + y = -9223372036854775807 + r = x + y + if r != 0 { + t.Errorf("9223372036854775807 + -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x + y + if r != 9223372032559808511 { + t.Errorf("9223372036854775807 + -4294967296 = %d, want 9223372032559808511", r) + } + y = -1 + r = x + y + if r != 9223372036854775806 { + t.Errorf("9223372036854775807 + -1 = %d, want 9223372036854775806", r) + } + y = 0 + r = x + y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 + 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x + y + if r != -9223372036854775808 { + t.Errorf("9223372036854775807 + 1 = %d, want -9223372036854775808", r) + } + y = 4294967296 + r = x + y + if r != -9223372032559808513 { + t.Errorf("9223372036854775807 + 4294967296 = %d, want -9223372032559808513", r) + } + y = 9223372036854775806 + r = x + y + if r != -3 { + t.Errorf("9223372036854775807 + 9223372036854775806 = %d, want -3", r) + } + y = 9223372036854775807 + r = x + y + if r != -2 { + t.Errorf("9223372036854775807 + 9223372036854775807 = %d, want -2", r) + } +} +func TestConstFoldint64sub(t *testing.T) { + var x, y, r int64 + x = -9223372036854775808 + y = -9223372036854775808 + r = x - y + if r != 0 { + t.Errorf("-9223372036854775808 - -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x - y + if r != -1 { + t.Errorf("-9223372036854775808 - -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x - y + if r != -9223372032559808512 { + t.Errorf("-9223372036854775808 - -4294967296 = %d, want -9223372032559808512", r) + } + y = -1 + r = x - y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775808 - -1 = %d, want -9223372036854775807", r) + } + y = 0 + r = x - y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 - 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x - y + if r != 9223372036854775807 { + t.Errorf("-9223372036854775808 - 1 = %d, want 9223372036854775807", r) + } + y = 4294967296 + r = x - y + if r != 9223372032559808512 { + t.Errorf("-9223372036854775808 - 4294967296 = %d, want 9223372032559808512", r) + } + y = 9223372036854775806 + r = x - y + if r != 2 { + t.Errorf("-9223372036854775808 - 9223372036854775806 = %d, want 2", r) + } + y = 9223372036854775807 + r = x - y + if r != 1 { + t.Errorf("-9223372036854775808 - 9223372036854775807 = %d, want 1", r) + } + x = -9223372036854775807 + y = -9223372036854775808 + r = x - y + if r != 1 { + t.Errorf("-9223372036854775807 - -9223372036854775808 = %d, want 1", r) + } + y = -9223372036854775807 + r = x - y + if r != 0 { + t.Errorf("-9223372036854775807 - -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x - y + if r != -9223372032559808511 { + t.Errorf("-9223372036854775807 - -4294967296 = %d, want -9223372032559808511", r) + } + y = -1 + r = x - y + if r != -9223372036854775806 { + t.Errorf("-9223372036854775807 - -1 = %d, want -9223372036854775806", r) + } + y = 0 + r = x - y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 - 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x - y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775807 - 1 = %d, want -9223372036854775808", r) + } + y = 4294967296 + r = x - y + if r != 9223372032559808513 { + t.Errorf("-9223372036854775807 - 4294967296 = %d, want 9223372032559808513", r) + } + y = 9223372036854775806 + r = x - y + if r != 3 { + t.Errorf("-9223372036854775807 - 9223372036854775806 = %d, want 3", r) + } + y = 9223372036854775807 + r = x - y + if r != 2 { + t.Errorf("-9223372036854775807 - 9223372036854775807 = %d, want 2", r) + } + x = -4294967296 + y = -9223372036854775808 + r = x - y + if r != 9223372032559808512 { + t.Errorf("-4294967296 - -9223372036854775808 = %d, want 9223372032559808512", r) + } + y = -9223372036854775807 + r = x - y + if r != 9223372032559808511 { + t.Errorf("-4294967296 - -9223372036854775807 = %d, want 9223372032559808511", r) + } + y = -4294967296 + r = x - y + if r != 0 { + t.Errorf("-4294967296 - -4294967296 = %d, want 0", r) + } + y = -1 + r = x - y + if r != -4294967295 { + t.Errorf("-4294967296 - -1 = %d, want -4294967295", r) + } + y = 0 + r = x - y + if r != -4294967296 { + t.Errorf("-4294967296 - 0 = %d, want -4294967296", r) + } + y = 1 + r = x - y + if r != -4294967297 { + t.Errorf("-4294967296 - 1 = %d, want -4294967297", r) + } + y = 4294967296 + r = x - y + if r != -8589934592 { + t.Errorf("-4294967296 - 4294967296 = %d, want -8589934592", r) + } + y = 9223372036854775806 + r = x - y + if r != 9223372032559808514 { + t.Errorf("-4294967296 - 9223372036854775806 = %d, want 9223372032559808514", r) + } + y = 9223372036854775807 + r = x - y + if r != 9223372032559808513 { + t.Errorf("-4294967296 - 9223372036854775807 = %d, want 9223372032559808513", r) + } + x = -1 + y = -9223372036854775808 + r = x - y + if r != 9223372036854775807 { + t.Errorf("-1 - -9223372036854775808 = %d, want 9223372036854775807", r) + } + y = -9223372036854775807 + r = x - y + if r != 9223372036854775806 { + t.Errorf("-1 - -9223372036854775807 = %d, want 9223372036854775806", r) + } + y = -4294967296 + r = x - y + if r != 4294967295 { + t.Errorf("-1 - -4294967296 = %d, want 4294967295", r) + } + y = -1 + r = x - y + if r != 0 { + t.Errorf("-1 - -1 = %d, want 0", r) + } + y = 0 + r = x - y + if r != -1 { + t.Errorf("-1 - 0 = %d, want -1", r) + } + y = 1 + r = x - y + if r != -2 { + t.Errorf("-1 - 1 = %d, want -2", r) + } + y = 4294967296 + r = x - y + if r != -4294967297 { + t.Errorf("-1 - 4294967296 = %d, want -4294967297", r) + } + y = 9223372036854775806 + r = x - y + if r != -9223372036854775807 { + t.Errorf("-1 - 9223372036854775806 = %d, want -9223372036854775807", r) + } + y = 9223372036854775807 + r = x - y + if r != -9223372036854775808 { + t.Errorf("-1 - 9223372036854775807 = %d, want -9223372036854775808", r) + } + x = 0 + y = -9223372036854775808 + r = x - y + if r != -9223372036854775808 { + t.Errorf("0 - -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x - y + if r != 9223372036854775807 { + t.Errorf("0 - -9223372036854775807 = %d, want 9223372036854775807", r) + } + y = -4294967296 + r = x - y + if r != 4294967296 { + t.Errorf("0 - -4294967296 = %d, want 4294967296", r) + } + y = -1 + r = x - y + if r != 1 { + t.Errorf("0 - -1 = %d, want 1", r) + } + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != -1 { + t.Errorf("0 - 1 = %d, want -1", r) + } + y = 4294967296 + r = x - y + if r != -4294967296 { + t.Errorf("0 - 4294967296 = %d, want -4294967296", r) + } + y = 9223372036854775806 + r = x - y + if r != -9223372036854775806 { + t.Errorf("0 - 9223372036854775806 = %d, want -9223372036854775806", r) + } + y = 9223372036854775807 + r = x - y + if r != -9223372036854775807 { + t.Errorf("0 - 9223372036854775807 = %d, want -9223372036854775807", r) + } + x = 1 + y = -9223372036854775808 + r = x - y + if r != -9223372036854775807 { + t.Errorf("1 - -9223372036854775808 = %d, want -9223372036854775807", r) + } + y = -9223372036854775807 + r = x - y + if r != -9223372036854775808 { + t.Errorf("1 - -9223372036854775807 = %d, want -9223372036854775808", r) + } + y = -4294967296 + r = x - y + if r != 4294967297 { + t.Errorf("1 - -4294967296 = %d, want 4294967297", r) + } + y = -1 + r = x - y + if r != 2 { + t.Errorf("1 - -1 = %d, want 2", r) + } + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 4294967296 + r = x - y + if r != -4294967295 { + t.Errorf("1 - 4294967296 = %d, want -4294967295", r) + } + y = 9223372036854775806 + r = x - y + if r != -9223372036854775805 { + t.Errorf("1 - 9223372036854775806 = %d, want -9223372036854775805", r) + } + y = 9223372036854775807 + r = x - y + if r != -9223372036854775806 { + t.Errorf("1 - 9223372036854775807 = %d, want -9223372036854775806", r) + } + x = 4294967296 + y = -9223372036854775808 + r = x - y + if r != -9223372032559808512 { + t.Errorf("4294967296 - -9223372036854775808 = %d, want -9223372032559808512", r) + } + y = -9223372036854775807 + r = x - y + if r != -9223372032559808513 { + t.Errorf("4294967296 - -9223372036854775807 = %d, want -9223372032559808513", r) + } + y = -4294967296 + r = x - y + if r != 8589934592 { + t.Errorf("4294967296 - -4294967296 = %d, want 8589934592", r) + } + y = -1 + r = x - y + if r != 4294967297 { + t.Errorf("4294967296 - -1 = %d, want 4294967297", r) + } + y = 0 + r = x - y + if r != 4294967296 { + t.Errorf("4294967296 - 0 = %d, want 4294967296", r) + } + y = 1 + r = x - y + if r != 4294967295 { + t.Errorf("4294967296 - 1 = %d, want 4294967295", r) + } + y = 4294967296 + r = x - y + if r != 0 { + t.Errorf("4294967296 - 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x - y + if r != -9223372032559808510 { + t.Errorf("4294967296 - 9223372036854775806 = %d, want -9223372032559808510", r) + } + y = 9223372036854775807 + r = x - y + if r != -9223372032559808511 { + t.Errorf("4294967296 - 9223372036854775807 = %d, want -9223372032559808511", r) + } + x = 9223372036854775806 + y = -9223372036854775808 + r = x - y + if r != -2 { + t.Errorf("9223372036854775806 - -9223372036854775808 = %d, want -2", r) + } + y = -9223372036854775807 + r = x - y + if r != -3 { + t.Errorf("9223372036854775806 - -9223372036854775807 = %d, want -3", r) + } + y = -4294967296 + r = x - y + if r != -9223372032559808514 { + t.Errorf("9223372036854775806 - -4294967296 = %d, want -9223372032559808514", r) + } + y = -1 + r = x - y + if r != 9223372036854775807 { + t.Errorf("9223372036854775806 - -1 = %d, want 9223372036854775807", r) + } + y = 0 + r = x - y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 - 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x - y + if r != 9223372036854775805 { + t.Errorf("9223372036854775806 - 1 = %d, want 9223372036854775805", r) + } + y = 4294967296 + r = x - y + if r != 9223372032559808510 { + t.Errorf("9223372036854775806 - 4294967296 = %d, want 9223372032559808510", r) + } + y = 9223372036854775806 + r = x - y + if r != 0 { + t.Errorf("9223372036854775806 - 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x - y + if r != -1 { + t.Errorf("9223372036854775806 - 9223372036854775807 = %d, want -1", r) + } + x = 9223372036854775807 + y = -9223372036854775808 + r = x - y + if r != -1 { + t.Errorf("9223372036854775807 - -9223372036854775808 = %d, want -1", r) + } + y = -9223372036854775807 + r = x - y + if r != -2 { + t.Errorf("9223372036854775807 - -9223372036854775807 = %d, want -2", r) + } + y = -4294967296 + r = x - y + if r != -9223372032559808513 { + t.Errorf("9223372036854775807 - -4294967296 = %d, want -9223372032559808513", r) + } + y = -1 + r = x - y + if r != -9223372036854775808 { + t.Errorf("9223372036854775807 - -1 = %d, want -9223372036854775808", r) + } + y = 0 + r = x - y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 - 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x - y + if r != 9223372036854775806 { + t.Errorf("9223372036854775807 - 1 = %d, want 9223372036854775806", r) + } + y = 4294967296 + r = x - y + if r != 9223372032559808511 { + t.Errorf("9223372036854775807 - 4294967296 = %d, want 9223372032559808511", r) + } + y = 9223372036854775806 + r = x - y + if r != 1 { + t.Errorf("9223372036854775807 - 9223372036854775806 = %d, want 1", r) + } + y = 9223372036854775807 + r = x - y + if r != 0 { + t.Errorf("9223372036854775807 - 9223372036854775807 = %d, want 0", r) + } +} +func TestConstFoldint64div(t *testing.T) { + var x, y, r int64 + x = -9223372036854775808 + y = -9223372036854775808 + r = x / y + if r != 1 { + t.Errorf("-9223372036854775808 / -9223372036854775808 = %d, want 1", r) + } + y = -9223372036854775807 + r = x / y + if r != 1 { + t.Errorf("-9223372036854775808 / -9223372036854775807 = %d, want 1", r) + } + y = -4294967296 + r = x / y + if r != 2147483648 { + t.Errorf("-9223372036854775808 / -4294967296 = %d, want 2147483648", r) + } + y = -1 + r = x / y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 / -1 = %d, want -9223372036854775808", r) + } + y = 1 + r = x / y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 / 1 = %d, want -9223372036854775808", r) + } + y = 4294967296 + r = x / y + if r != -2147483648 { + t.Errorf("-9223372036854775808 / 4294967296 = %d, want -2147483648", r) + } + y = 9223372036854775806 + r = x / y + if r != -1 { + t.Errorf("-9223372036854775808 / 9223372036854775806 = %d, want -1", r) + } + y = 9223372036854775807 + r = x / y + if r != -1 { + t.Errorf("-9223372036854775808 / 9223372036854775807 = %d, want -1", r) + } + x = -9223372036854775807 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("-9223372036854775807 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 1 { + t.Errorf("-9223372036854775807 / -9223372036854775807 = %d, want 1", r) + } + y = -4294967296 + r = x / y + if r != 2147483647 { + t.Errorf("-9223372036854775807 / -4294967296 = %d, want 2147483647", r) + } + y = -1 + r = x / y + if r != 9223372036854775807 { + t.Errorf("-9223372036854775807 / -1 = %d, want 9223372036854775807", r) + } + y = 1 + r = x / y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 / 1 = %d, want -9223372036854775807", r) + } + y = 4294967296 + r = x / y + if r != -2147483647 { + t.Errorf("-9223372036854775807 / 4294967296 = %d, want -2147483647", r) + } + y = 9223372036854775806 + r = x / y + if r != -1 { + t.Errorf("-9223372036854775807 / 9223372036854775806 = %d, want -1", r) + } + y = 9223372036854775807 + r = x / y + if r != -1 { + t.Errorf("-9223372036854775807 / 9223372036854775807 = %d, want -1", r) + } + x = -4294967296 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("-4294967296 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("-4294967296 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != 1 { + t.Errorf("-4294967296 / -4294967296 = %d, want 1", r) + } + y = -1 + r = x / y + if r != 4294967296 { + t.Errorf("-4294967296 / -1 = %d, want 4294967296", r) + } + y = 1 + r = x / y + if r != -4294967296 { + t.Errorf("-4294967296 / 1 = %d, want -4294967296", r) + } + y = 4294967296 + r = x / y + if r != -1 { + t.Errorf("-4294967296 / 4294967296 = %d, want -1", r) + } + y = 9223372036854775806 + r = x / y + if r != 0 { + t.Errorf("-4294967296 / 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("-4294967296 / 9223372036854775807 = %d, want 0", r) + } + x = -1 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("-1 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("-1 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != 0 { + t.Errorf("-1 / -4294967296 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 1 { + t.Errorf("-1 / -1 = %d, want 1", r) + } + y = 1 + r = x / y + if r != -1 { + t.Errorf("-1 / 1 = %d, want -1", r) + } + y = 4294967296 + r = x / y + if r != 0 { + t.Errorf("-1 / 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x / y + if r != 0 { + t.Errorf("-1 / 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("-1 / 9223372036854775807 = %d, want 0", r) + } + x = 0 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("0 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("0 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != 0 { + t.Errorf("0 / -4294967296 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 0 { + t.Errorf("0 / -1 = %d, want 0", r) + } + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 4294967296 + r = x / y + if r != 0 { + t.Errorf("0 / 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x / y + if r != 0 { + t.Errorf("0 / 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("0 / 9223372036854775807 = %d, want 0", r) + } + x = 1 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("1 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("1 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != 0 { + t.Errorf("1 / -4294967296 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -1 { + t.Errorf("1 / -1 = %d, want -1", r) + } + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 4294967296 + r = x / y + if r != 0 { + t.Errorf("1 / 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x / y + if r != 0 { + t.Errorf("1 / 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("1 / 9223372036854775807 = %d, want 0", r) + } + x = 4294967296 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("4294967296 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("4294967296 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != -1 { + t.Errorf("4294967296 / -4294967296 = %d, want -1", r) + } + y = -1 + r = x / y + if r != -4294967296 { + t.Errorf("4294967296 / -1 = %d, want -4294967296", r) + } + y = 1 + r = x / y + if r != 4294967296 { + t.Errorf("4294967296 / 1 = %d, want 4294967296", r) + } + y = 4294967296 + r = x / y + if r != 1 { + t.Errorf("4294967296 / 4294967296 = %d, want 1", r) + } + y = 9223372036854775806 + r = x / y + if r != 0 { + t.Errorf("4294967296 / 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("4294967296 / 9223372036854775807 = %d, want 0", r) + } + x = 9223372036854775806 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("9223372036854775806 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("9223372036854775806 / -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x / y + if r != -2147483647 { + t.Errorf("9223372036854775806 / -4294967296 = %d, want -2147483647", r) + } + y = -1 + r = x / y + if r != -9223372036854775806 { + t.Errorf("9223372036854775806 / -1 = %d, want -9223372036854775806", r) + } + y = 1 + r = x / y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 / 1 = %d, want 9223372036854775806", r) + } + y = 4294967296 + r = x / y + if r != 2147483647 { + t.Errorf("9223372036854775806 / 4294967296 = %d, want 2147483647", r) + } + y = 9223372036854775806 + r = x / y + if r != 1 { + t.Errorf("9223372036854775806 / 9223372036854775806 = %d, want 1", r) + } + y = 9223372036854775807 + r = x / y + if r != 0 { + t.Errorf("9223372036854775806 / 9223372036854775807 = %d, want 0", r) + } + x = 9223372036854775807 + y = -9223372036854775808 + r = x / y + if r != 0 { + t.Errorf("9223372036854775807 / -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x / y + if r != -1 { + t.Errorf("9223372036854775807 / -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x / y + if r != -2147483647 { + t.Errorf("9223372036854775807 / -4294967296 = %d, want -2147483647", r) + } + y = -1 + r = x / y + if r != -9223372036854775807 { + t.Errorf("9223372036854775807 / -1 = %d, want -9223372036854775807", r) + } + y = 1 + r = x / y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 / 1 = %d, want 9223372036854775807", r) + } + y = 4294967296 + r = x / y + if r != 2147483647 { + t.Errorf("9223372036854775807 / 4294967296 = %d, want 2147483647", r) + } + y = 9223372036854775806 + r = x / y + if r != 1 { + t.Errorf("9223372036854775807 / 9223372036854775806 = %d, want 1", r) + } + y = 9223372036854775807 + r = x / y + if r != 1 { + t.Errorf("9223372036854775807 / 9223372036854775807 = %d, want 1", r) + } +} +func TestConstFoldint64mul(t *testing.T) { + var x, y, r int64 + x = -9223372036854775808 + y = -9223372036854775808 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775808 * -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 * -9223372036854775807 = %d, want -9223372036854775808", r) + } + y = -4294967296 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775808 * -4294967296 = %d, want 0", r) + } + y = -1 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 * -1 = %d, want -9223372036854775808", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775808 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 * 1 = %d, want -9223372036854775808", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775808 * 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775808 * 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 * 9223372036854775807 = %d, want -9223372036854775808", r) + } + x = -9223372036854775807 + y = -9223372036854775808 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x * y + if r != 1 { + t.Errorf("-9223372036854775807 * -9223372036854775807 = %d, want 1", r) + } + y = -4294967296 + r = x * y + if r != -4294967296 { + t.Errorf("-9223372036854775807 * -4294967296 = %d, want -4294967296", r) + } + y = -1 + r = x * y + if r != 9223372036854775807 { + t.Errorf("-9223372036854775807 * -1 = %d, want 9223372036854775807", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-9223372036854775807 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 * 1 = %d, want -9223372036854775807", r) + } + y = 4294967296 + r = x * y + if r != 4294967296 { + t.Errorf("-9223372036854775807 * 4294967296 = %d, want 4294967296", r) + } + y = 9223372036854775806 + r = x * y + if r != 9223372036854775806 { + t.Errorf("-9223372036854775807 * 9223372036854775806 = %d, want 9223372036854775806", r) + } + y = 9223372036854775807 + r = x * y + if r != -1 { + t.Errorf("-9223372036854775807 * 9223372036854775807 = %d, want -1", r) + } + x = -4294967296 + y = -9223372036854775808 + r = x * y + if r != 0 { + t.Errorf("-4294967296 * -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x * y + if r != -4294967296 { + t.Errorf("-4294967296 * -9223372036854775807 = %d, want -4294967296", r) + } + y = -4294967296 + r = x * y + if r != 0 { + t.Errorf("-4294967296 * -4294967296 = %d, want 0", r) + } + y = -1 + r = x * y + if r != 4294967296 { + t.Errorf("-4294967296 * -1 = %d, want 4294967296", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-4294967296 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -4294967296 { + t.Errorf("-4294967296 * 1 = %d, want -4294967296", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("-4294967296 * 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x * y + if r != 8589934592 { + t.Errorf("-4294967296 * 9223372036854775806 = %d, want 8589934592", r) + } + y = 9223372036854775807 + r = x * y + if r != 4294967296 { + t.Errorf("-4294967296 * 9223372036854775807 = %d, want 4294967296", r) + } + x = -1 + y = -9223372036854775808 + r = x * y + if r != -9223372036854775808 { + t.Errorf("-1 * -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x * y + if r != 9223372036854775807 { + t.Errorf("-1 * -9223372036854775807 = %d, want 9223372036854775807", r) + } + y = -4294967296 + r = x * y + if r != 4294967296 { + t.Errorf("-1 * -4294967296 = %d, want 4294967296", r) + } + y = -1 + r = x * y + if r != 1 { + t.Errorf("-1 * -1 = %d, want 1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -1 { + t.Errorf("-1 * 1 = %d, want -1", r) + } + y = 4294967296 + r = x * y + if r != -4294967296 { + t.Errorf("-1 * 4294967296 = %d, want -4294967296", r) + } + y = 9223372036854775806 + r = x * y + if r != -9223372036854775806 { + t.Errorf("-1 * 9223372036854775806 = %d, want -9223372036854775806", r) + } + y = 9223372036854775807 + r = x * y + if r != -9223372036854775807 { + t.Errorf("-1 * 9223372036854775807 = %d, want -9223372036854775807", r) + } + x = 0 + y = -9223372036854775808 + r = x * y + if r != 0 { + t.Errorf("0 * -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x * y + if r != 0 { + t.Errorf("0 * -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x * y + if r != 0 { + t.Errorf("0 * -4294967296 = %d, want 0", r) + } + y = -1 + r = x * y + if r != 0 { + t.Errorf("0 * -1 = %d, want 0", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("0 * 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x * y + if r != 0 { + t.Errorf("0 * 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x * y + if r != 0 { + t.Errorf("0 * 9223372036854775807 = %d, want 0", r) + } + x = 1 + y = -9223372036854775808 + r = x * y + if r != -9223372036854775808 { + t.Errorf("1 * -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x * y + if r != -9223372036854775807 { + t.Errorf("1 * -9223372036854775807 = %d, want -9223372036854775807", r) + } + y = -4294967296 + r = x * y + if r != -4294967296 { + t.Errorf("1 * -4294967296 = %d, want -4294967296", r) + } + y = -1 + r = x * y + if r != -1 { + t.Errorf("1 * -1 = %d, want -1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 4294967296 + r = x * y + if r != 4294967296 { + t.Errorf("1 * 4294967296 = %d, want 4294967296", r) + } + y = 9223372036854775806 + r = x * y + if r != 9223372036854775806 { + t.Errorf("1 * 9223372036854775806 = %d, want 9223372036854775806", r) + } + y = 9223372036854775807 + r = x * y + if r != 9223372036854775807 { + t.Errorf("1 * 9223372036854775807 = %d, want 9223372036854775807", r) + } + x = 4294967296 + y = -9223372036854775808 + r = x * y + if r != 0 { + t.Errorf("4294967296 * -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x * y + if r != 4294967296 { + t.Errorf("4294967296 * -9223372036854775807 = %d, want 4294967296", r) + } + y = -4294967296 + r = x * y + if r != 0 { + t.Errorf("4294967296 * -4294967296 = %d, want 0", r) + } + y = -1 + r = x * y + if r != -4294967296 { + t.Errorf("4294967296 * -1 = %d, want -4294967296", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("4294967296 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 4294967296 { + t.Errorf("4294967296 * 1 = %d, want 4294967296", r) + } + y = 4294967296 + r = x * y + if r != 0 { + t.Errorf("4294967296 * 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x * y + if r != -8589934592 { + t.Errorf("4294967296 * 9223372036854775806 = %d, want -8589934592", r) + } + y = 9223372036854775807 + r = x * y + if r != -4294967296 { + t.Errorf("4294967296 * 9223372036854775807 = %d, want -4294967296", r) + } + x = 9223372036854775806 + y = -9223372036854775808 + r = x * y + if r != 0 { + t.Errorf("9223372036854775806 * -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x * y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 * -9223372036854775807 = %d, want 9223372036854775806", r) + } + y = -4294967296 + r = x * y + if r != 8589934592 { + t.Errorf("9223372036854775806 * -4294967296 = %d, want 8589934592", r) + } + y = -1 + r = x * y + if r != -9223372036854775806 { + t.Errorf("9223372036854775806 * -1 = %d, want -9223372036854775806", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("9223372036854775806 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 * 1 = %d, want 9223372036854775806", r) + } + y = 4294967296 + r = x * y + if r != -8589934592 { + t.Errorf("9223372036854775806 * 4294967296 = %d, want -8589934592", r) + } + y = 9223372036854775806 + r = x * y + if r != 4 { + t.Errorf("9223372036854775806 * 9223372036854775806 = %d, want 4", r) + } + y = 9223372036854775807 + r = x * y + if r != -9223372036854775806 { + t.Errorf("9223372036854775806 * 9223372036854775807 = %d, want -9223372036854775806", r) + } + x = 9223372036854775807 + y = -9223372036854775808 + r = x * y + if r != -9223372036854775808 { + t.Errorf("9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r) + } + y = -9223372036854775807 + r = x * y + if r != -1 { + t.Errorf("9223372036854775807 * -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x * y + if r != 4294967296 { + t.Errorf("9223372036854775807 * -4294967296 = %d, want 4294967296", r) + } + y = -1 + r = x * y + if r != -9223372036854775807 { + t.Errorf("9223372036854775807 * -1 = %d, want -9223372036854775807", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("9223372036854775807 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 * 1 = %d, want 9223372036854775807", r) + } + y = 4294967296 + r = x * y + if r != -4294967296 { + t.Errorf("9223372036854775807 * 4294967296 = %d, want -4294967296", r) + } + y = 9223372036854775806 + r = x * y + if r != -9223372036854775806 { + t.Errorf("9223372036854775807 * 9223372036854775806 = %d, want -9223372036854775806", r) + } + y = 9223372036854775807 + r = x * y + if r != 1 { + t.Errorf("9223372036854775807 * 9223372036854775807 = %d, want 1", r) + } +} +func TestConstFoldint64mod(t *testing.T) { + var x, y, r int64 + x = -9223372036854775808 + y = -9223372036854775808 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775808 % -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x % y + if r != -1 { + t.Errorf("-9223372036854775808 % -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775808 % -4294967296 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775808 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775808 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775808 % 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x % y + if r != -2 { + t.Errorf("-9223372036854775808 % 9223372036854775806 = %d, want -2", r) + } + y = 9223372036854775807 + r = x % y + if r != -1 { + t.Errorf("-9223372036854775808 % 9223372036854775807 = %d, want -1", r) + } + x = -9223372036854775807 + y = -9223372036854775808 + r = x % y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 % -9223372036854775808 = %d, want -9223372036854775807", r) + } + y = -9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775807 % -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x % y + if r != -4294967295 { + t.Errorf("-9223372036854775807 % -4294967296 = %d, want -4294967295", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775807 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775807 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != -4294967295 { + t.Errorf("-9223372036854775807 % 4294967296 = %d, want -4294967295", r) + } + y = 9223372036854775806 + r = x % y + if r != -1 { + t.Errorf("-9223372036854775807 % 9223372036854775806 = %d, want -1", r) + } + y = 9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("-9223372036854775807 % 9223372036854775807 = %d, want 0", r) + } + x = -4294967296 + y = -9223372036854775808 + r = x % y + if r != -4294967296 { + t.Errorf("-4294967296 % -9223372036854775808 = %d, want -4294967296", r) + } + y = -9223372036854775807 + r = x % y + if r != -4294967296 { + t.Errorf("-4294967296 % -9223372036854775807 = %d, want -4294967296", r) + } + y = -4294967296 + r = x % y + if r != 0 { + t.Errorf("-4294967296 % -4294967296 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-4294967296 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-4294967296 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("-4294967296 % 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x % y + if r != -4294967296 { + t.Errorf("-4294967296 % 9223372036854775806 = %d, want -4294967296", r) + } + y = 9223372036854775807 + r = x % y + if r != -4294967296 { + t.Errorf("-4294967296 % 9223372036854775807 = %d, want -4294967296", r) + } + x = -1 + y = -9223372036854775808 + r = x % y + if r != -1 { + t.Errorf("-1 % -9223372036854775808 = %d, want -1", r) + } + y = -9223372036854775807 + r = x % y + if r != -1 { + t.Errorf("-1 % -9223372036854775807 = %d, want -1", r) + } + y = -4294967296 + r = x % y + if r != -1 { + t.Errorf("-1 % -4294967296 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-1 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != -1 { + t.Errorf("-1 % 4294967296 = %d, want -1", r) + } + y = 9223372036854775806 + r = x % y + if r != -1 { + t.Errorf("-1 % 9223372036854775806 = %d, want -1", r) + } + y = 9223372036854775807 + r = x % y + if r != -1 { + t.Errorf("-1 % 9223372036854775807 = %d, want -1", r) + } + x = 0 + y = -9223372036854775808 + r = x % y + if r != 0 { + t.Errorf("0 % -9223372036854775808 = %d, want 0", r) + } + y = -9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("0 % -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x % y + if r != 0 { + t.Errorf("0 % -4294967296 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("0 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("0 % 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x % y + if r != 0 { + t.Errorf("0 % 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("0 % 9223372036854775807 = %d, want 0", r) + } + x = 1 + y = -9223372036854775808 + r = x % y + if r != 1 { + t.Errorf("1 % -9223372036854775808 = %d, want 1", r) + } + y = -9223372036854775807 + r = x % y + if r != 1 { + t.Errorf("1 % -9223372036854775807 = %d, want 1", r) + } + y = -4294967296 + r = x % y + if r != 1 { + t.Errorf("1 % -4294967296 = %d, want 1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 1 { + t.Errorf("1 % 4294967296 = %d, want 1", r) + } + y = 9223372036854775806 + r = x % y + if r != 1 { + t.Errorf("1 % 9223372036854775806 = %d, want 1", r) + } + y = 9223372036854775807 + r = x % y + if r != 1 { + t.Errorf("1 % 9223372036854775807 = %d, want 1", r) + } + x = 4294967296 + y = -9223372036854775808 + r = x % y + if r != 4294967296 { + t.Errorf("4294967296 % -9223372036854775808 = %d, want 4294967296", r) + } + y = -9223372036854775807 + r = x % y + if r != 4294967296 { + t.Errorf("4294967296 % -9223372036854775807 = %d, want 4294967296", r) + } + y = -4294967296 + r = x % y + if r != 0 { + t.Errorf("4294967296 % -4294967296 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("4294967296 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("4294967296 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 0 { + t.Errorf("4294967296 % 4294967296 = %d, want 0", r) + } + y = 9223372036854775806 + r = x % y + if r != 4294967296 { + t.Errorf("4294967296 % 9223372036854775806 = %d, want 4294967296", r) + } + y = 9223372036854775807 + r = x % y + if r != 4294967296 { + t.Errorf("4294967296 % 9223372036854775807 = %d, want 4294967296", r) + } + x = 9223372036854775806 + y = -9223372036854775808 + r = x % y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 % -9223372036854775808 = %d, want 9223372036854775806", r) + } + y = -9223372036854775807 + r = x % y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 % -9223372036854775807 = %d, want 9223372036854775806", r) + } + y = -4294967296 + r = x % y + if r != 4294967294 { + t.Errorf("9223372036854775806 % -4294967296 = %d, want 4294967294", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("9223372036854775806 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("9223372036854775806 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 4294967294 { + t.Errorf("9223372036854775806 % 4294967296 = %d, want 4294967294", r) + } + y = 9223372036854775806 + r = x % y + if r != 0 { + t.Errorf("9223372036854775806 % 9223372036854775806 = %d, want 0", r) + } + y = 9223372036854775807 + r = x % y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 % 9223372036854775807 = %d, want 9223372036854775806", r) + } + x = 9223372036854775807 + y = -9223372036854775808 + r = x % y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 % -9223372036854775808 = %d, want 9223372036854775807", r) + } + y = -9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("9223372036854775807 % -9223372036854775807 = %d, want 0", r) + } + y = -4294967296 + r = x % y + if r != 4294967295 { + t.Errorf("9223372036854775807 % -4294967296 = %d, want 4294967295", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("9223372036854775807 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("9223372036854775807 % 1 = %d, want 0", r) + } + y = 4294967296 + r = x % y + if r != 4294967295 { + t.Errorf("9223372036854775807 % 4294967296 = %d, want 4294967295", r) + } + y = 9223372036854775806 + r = x % y + if r != 1 { + t.Errorf("9223372036854775807 % 9223372036854775806 = %d, want 1", r) + } + y = 9223372036854775807 + r = x % y + if r != 0 { + t.Errorf("9223372036854775807 % 9223372036854775807 = %d, want 0", r) + } +} +func TestConstFolduint32add(t *testing.T) { + var x, y, r uint32 + x = 0 + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 4294967295 + r = x + y + if r != 4294967295 { + t.Errorf("0 + 4294967295 = %d, want 4294967295", r) + } + x = 1 + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 4294967295 + r = x + y + if r != 0 { + t.Errorf("1 + 4294967295 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x + y + if r != 4294967295 { + t.Errorf("4294967295 + 0 = %d, want 4294967295", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("4294967295 + 1 = %d, want 0", r) + } + y = 4294967295 + r = x + y + if r != 4294967294 { + t.Errorf("4294967295 + 4294967295 = %d, want 4294967294", r) + } +} +func TestConstFolduint32sub(t *testing.T) { + var x, y, r uint32 + x = 0 + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != 4294967295 { + t.Errorf("0 - 1 = %d, want 4294967295", r) + } + y = 4294967295 + r = x - y + if r != 1 { + t.Errorf("0 - 4294967295 = %d, want 1", r) + } + x = 1 + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 4294967295 + r = x - y + if r != 2 { + t.Errorf("1 - 4294967295 = %d, want 2", r) + } + x = 4294967295 + y = 0 + r = x - y + if r != 4294967295 { + t.Errorf("4294967295 - 0 = %d, want 4294967295", r) + } + y = 1 + r = x - y + if r != 4294967294 { + t.Errorf("4294967295 - 1 = %d, want 4294967294", r) + } + y = 4294967295 + r = x - y + if r != 0 { + t.Errorf("4294967295 - 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint32div(t *testing.T) { + var x, y, r uint32 + x = 0 + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 4294967295 + r = x / y + if r != 0 { + t.Errorf("0 / 4294967295 = %d, want 0", r) + } + x = 1 + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 4294967295 + r = x / y + if r != 0 { + t.Errorf("1 / 4294967295 = %d, want 0", r) + } + x = 4294967295 + y = 1 + r = x / y + if r != 4294967295 { + t.Errorf("4294967295 / 1 = %d, want 4294967295", r) + } + y = 4294967295 + r = x / y + if r != 1 { + t.Errorf("4294967295 / 4294967295 = %d, want 1", r) + } +} +func TestConstFolduint32mul(t *testing.T) { + var x, y, r uint32 + x = 0 + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 4294967295 + r = x * y + if r != 0 { + t.Errorf("0 * 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 4294967295 + r = x * y + if r != 4294967295 { + t.Errorf("1 * 4294967295 = %d, want 4294967295", r) + } + x = 4294967295 + y = 0 + r = x * y + if r != 0 { + t.Errorf("4294967295 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 4294967295 { + t.Errorf("4294967295 * 1 = %d, want 4294967295", r) + } + y = 4294967295 + r = x * y + if r != 1 { + t.Errorf("4294967295 * 4294967295 = %d, want 1", r) + } +} +func TestConstFolduint32mod(t *testing.T) { + var x, y, r uint32 + x = 0 + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 4294967295 + r = x % y + if r != 0 { + t.Errorf("0 % 4294967295 = %d, want 0", r) + } + x = 1 + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 4294967295 + r = x % y + if r != 1 { + t.Errorf("1 % 4294967295 = %d, want 1", r) + } + x = 4294967295 + y = 1 + r = x % y + if r != 0 { + t.Errorf("4294967295 % 1 = %d, want 0", r) + } + y = 4294967295 + r = x % y + if r != 0 { + t.Errorf("4294967295 % 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint32add(t *testing.T) { + var x, y, r int32 + x = -2147483648 + y = -2147483648 + r = x + y + if r != 0 { + t.Errorf("-2147483648 + -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x + y + if r != 1 { + t.Errorf("-2147483648 + -2147483647 = %d, want 1", r) + } + y = -1 + r = x + y + if r != 2147483647 { + t.Errorf("-2147483648 + -1 = %d, want 2147483647", r) + } + y = 0 + r = x + y + if r != -2147483648 { + t.Errorf("-2147483648 + 0 = %d, want -2147483648", r) + } + y = 1 + r = x + y + if r != -2147483647 { + t.Errorf("-2147483648 + 1 = %d, want -2147483647", r) + } + y = 2147483647 + r = x + y + if r != -1 { + t.Errorf("-2147483648 + 2147483647 = %d, want -1", r) + } + x = -2147483647 + y = -2147483648 + r = x + y + if r != 1 { + t.Errorf("-2147483647 + -2147483648 = %d, want 1", r) + } + y = -2147483647 + r = x + y + if r != 2 { + t.Errorf("-2147483647 + -2147483647 = %d, want 2", r) + } + y = -1 + r = x + y + if r != -2147483648 { + t.Errorf("-2147483647 + -1 = %d, want -2147483648", r) + } + y = 0 + r = x + y + if r != -2147483647 { + t.Errorf("-2147483647 + 0 = %d, want -2147483647", r) + } + y = 1 + r = x + y + if r != -2147483646 { + t.Errorf("-2147483647 + 1 = %d, want -2147483646", r) + } + y = 2147483647 + r = x + y + if r != 0 { + t.Errorf("-2147483647 + 2147483647 = %d, want 0", r) + } + x = -1 + y = -2147483648 + r = x + y + if r != 2147483647 { + t.Errorf("-1 + -2147483648 = %d, want 2147483647", r) + } + y = -2147483647 + r = x + y + if r != -2147483648 { + t.Errorf("-1 + -2147483647 = %d, want -2147483648", r) + } + y = -1 + r = x + y + if r != -2 { + t.Errorf("-1 + -1 = %d, want -2", r) + } + y = 0 + r = x + y + if r != -1 { + t.Errorf("-1 + 0 = %d, want -1", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("-1 + 1 = %d, want 0", r) + } + y = 2147483647 + r = x + y + if r != 2147483646 { + t.Errorf("-1 + 2147483647 = %d, want 2147483646", r) + } + x = 0 + y = -2147483648 + r = x + y + if r != -2147483648 { + t.Errorf("0 + -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x + y + if r != -2147483647 { + t.Errorf("0 + -2147483647 = %d, want -2147483647", r) + } + y = -1 + r = x + y + if r != -1 { + t.Errorf("0 + -1 = %d, want -1", r) + } + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 2147483647 + r = x + y + if r != 2147483647 { + t.Errorf("0 + 2147483647 = %d, want 2147483647", r) + } + x = 1 + y = -2147483648 + r = x + y + if r != -2147483647 { + t.Errorf("1 + -2147483648 = %d, want -2147483647", r) + } + y = -2147483647 + r = x + y + if r != -2147483646 { + t.Errorf("1 + -2147483647 = %d, want -2147483646", r) + } + y = -1 + r = x + y + if r != 0 { + t.Errorf("1 + -1 = %d, want 0", r) + } + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 2147483647 + r = x + y + if r != -2147483648 { + t.Errorf("1 + 2147483647 = %d, want -2147483648", r) + } + x = 2147483647 + y = -2147483648 + r = x + y + if r != -1 { + t.Errorf("2147483647 + -2147483648 = %d, want -1", r) + } + y = -2147483647 + r = x + y + if r != 0 { + t.Errorf("2147483647 + -2147483647 = %d, want 0", r) + } + y = -1 + r = x + y + if r != 2147483646 { + t.Errorf("2147483647 + -1 = %d, want 2147483646", r) + } + y = 0 + r = x + y + if r != 2147483647 { + t.Errorf("2147483647 + 0 = %d, want 2147483647", r) + } + y = 1 + r = x + y + if r != -2147483648 { + t.Errorf("2147483647 + 1 = %d, want -2147483648", r) + } + y = 2147483647 + r = x + y + if r != -2 { + t.Errorf("2147483647 + 2147483647 = %d, want -2", r) + } +} +func TestConstFoldint32sub(t *testing.T) { + var x, y, r int32 + x = -2147483648 + y = -2147483648 + r = x - y + if r != 0 { + t.Errorf("-2147483648 - -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x - y + if r != -1 { + t.Errorf("-2147483648 - -2147483647 = %d, want -1", r) + } + y = -1 + r = x - y + if r != -2147483647 { + t.Errorf("-2147483648 - -1 = %d, want -2147483647", r) + } + y = 0 + r = x - y + if r != -2147483648 { + t.Errorf("-2147483648 - 0 = %d, want -2147483648", r) + } + y = 1 + r = x - y + if r != 2147483647 { + t.Errorf("-2147483648 - 1 = %d, want 2147483647", r) + } + y = 2147483647 + r = x - y + if r != 1 { + t.Errorf("-2147483648 - 2147483647 = %d, want 1", r) + } + x = -2147483647 + y = -2147483648 + r = x - y + if r != 1 { + t.Errorf("-2147483647 - -2147483648 = %d, want 1", r) + } + y = -2147483647 + r = x - y + if r != 0 { + t.Errorf("-2147483647 - -2147483647 = %d, want 0", r) + } + y = -1 + r = x - y + if r != -2147483646 { + t.Errorf("-2147483647 - -1 = %d, want -2147483646", r) + } + y = 0 + r = x - y + if r != -2147483647 { + t.Errorf("-2147483647 - 0 = %d, want -2147483647", r) + } + y = 1 + r = x - y + if r != -2147483648 { + t.Errorf("-2147483647 - 1 = %d, want -2147483648", r) + } + y = 2147483647 + r = x - y + if r != 2 { + t.Errorf("-2147483647 - 2147483647 = %d, want 2", r) + } + x = -1 + y = -2147483648 + r = x - y + if r != 2147483647 { + t.Errorf("-1 - -2147483648 = %d, want 2147483647", r) + } + y = -2147483647 + r = x - y + if r != 2147483646 { + t.Errorf("-1 - -2147483647 = %d, want 2147483646", r) + } + y = -1 + r = x - y + if r != 0 { + t.Errorf("-1 - -1 = %d, want 0", r) + } + y = 0 + r = x - y + if r != -1 { + t.Errorf("-1 - 0 = %d, want -1", r) + } + y = 1 + r = x - y + if r != -2 { + t.Errorf("-1 - 1 = %d, want -2", r) + } + y = 2147483647 + r = x - y + if r != -2147483648 { + t.Errorf("-1 - 2147483647 = %d, want -2147483648", r) + } + x = 0 + y = -2147483648 + r = x - y + if r != -2147483648 { + t.Errorf("0 - -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x - y + if r != 2147483647 { + t.Errorf("0 - -2147483647 = %d, want 2147483647", r) + } + y = -1 + r = x - y + if r != 1 { + t.Errorf("0 - -1 = %d, want 1", r) + } + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != -1 { + t.Errorf("0 - 1 = %d, want -1", r) + } + y = 2147483647 + r = x - y + if r != -2147483647 { + t.Errorf("0 - 2147483647 = %d, want -2147483647", r) + } + x = 1 + y = -2147483648 + r = x - y + if r != -2147483647 { + t.Errorf("1 - -2147483648 = %d, want -2147483647", r) + } + y = -2147483647 + r = x - y + if r != -2147483648 { + t.Errorf("1 - -2147483647 = %d, want -2147483648", r) + } + y = -1 + r = x - y + if r != 2 { + t.Errorf("1 - -1 = %d, want 2", r) + } + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 2147483647 + r = x - y + if r != -2147483646 { + t.Errorf("1 - 2147483647 = %d, want -2147483646", r) + } + x = 2147483647 + y = -2147483648 + r = x - y + if r != -1 { + t.Errorf("2147483647 - -2147483648 = %d, want -1", r) + } + y = -2147483647 + r = x - y + if r != -2 { + t.Errorf("2147483647 - -2147483647 = %d, want -2", r) + } + y = -1 + r = x - y + if r != -2147483648 { + t.Errorf("2147483647 - -1 = %d, want -2147483648", r) + } + y = 0 + r = x - y + if r != 2147483647 { + t.Errorf("2147483647 - 0 = %d, want 2147483647", r) + } + y = 1 + r = x - y + if r != 2147483646 { + t.Errorf("2147483647 - 1 = %d, want 2147483646", r) + } + y = 2147483647 + r = x - y + if r != 0 { + t.Errorf("2147483647 - 2147483647 = %d, want 0", r) + } +} +func TestConstFoldint32div(t *testing.T) { + var x, y, r int32 + x = -2147483648 + y = -2147483648 + r = x / y + if r != 1 { + t.Errorf("-2147483648 / -2147483648 = %d, want 1", r) + } + y = -2147483647 + r = x / y + if r != 1 { + t.Errorf("-2147483648 / -2147483647 = %d, want 1", r) + } + y = -1 + r = x / y + if r != -2147483648 { + t.Errorf("-2147483648 / -1 = %d, want -2147483648", r) + } + y = 1 + r = x / y + if r != -2147483648 { + t.Errorf("-2147483648 / 1 = %d, want -2147483648", r) + } + y = 2147483647 + r = x / y + if r != -1 { + t.Errorf("-2147483648 / 2147483647 = %d, want -1", r) + } + x = -2147483647 + y = -2147483648 + r = x / y + if r != 0 { + t.Errorf("-2147483647 / -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x / y + if r != 1 { + t.Errorf("-2147483647 / -2147483647 = %d, want 1", r) + } + y = -1 + r = x / y + if r != 2147483647 { + t.Errorf("-2147483647 / -1 = %d, want 2147483647", r) + } + y = 1 + r = x / y + if r != -2147483647 { + t.Errorf("-2147483647 / 1 = %d, want -2147483647", r) + } + y = 2147483647 + r = x / y + if r != -1 { + t.Errorf("-2147483647 / 2147483647 = %d, want -1", r) + } + x = -1 + y = -2147483648 + r = x / y + if r != 0 { + t.Errorf("-1 / -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x / y + if r != 0 { + t.Errorf("-1 / -2147483647 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 1 { + t.Errorf("-1 / -1 = %d, want 1", r) + } + y = 1 + r = x / y + if r != -1 { + t.Errorf("-1 / 1 = %d, want -1", r) + } + y = 2147483647 + r = x / y + if r != 0 { + t.Errorf("-1 / 2147483647 = %d, want 0", r) + } + x = 0 + y = -2147483648 + r = x / y + if r != 0 { + t.Errorf("0 / -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x / y + if r != 0 { + t.Errorf("0 / -2147483647 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 0 { + t.Errorf("0 / -1 = %d, want 0", r) + } + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 2147483647 + r = x / y + if r != 0 { + t.Errorf("0 / 2147483647 = %d, want 0", r) + } + x = 1 + y = -2147483648 + r = x / y + if r != 0 { + t.Errorf("1 / -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x / y + if r != 0 { + t.Errorf("1 / -2147483647 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -1 { + t.Errorf("1 / -1 = %d, want -1", r) + } + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 2147483647 + r = x / y + if r != 0 { + t.Errorf("1 / 2147483647 = %d, want 0", r) + } + x = 2147483647 + y = -2147483648 + r = x / y + if r != 0 { + t.Errorf("2147483647 / -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x / y + if r != -1 { + t.Errorf("2147483647 / -2147483647 = %d, want -1", r) + } + y = -1 + r = x / y + if r != -2147483647 { + t.Errorf("2147483647 / -1 = %d, want -2147483647", r) + } + y = 1 + r = x / y + if r != 2147483647 { + t.Errorf("2147483647 / 1 = %d, want 2147483647", r) + } + y = 2147483647 + r = x / y + if r != 1 { + t.Errorf("2147483647 / 2147483647 = %d, want 1", r) + } +} +func TestConstFoldint32mul(t *testing.T) { + var x, y, r int32 + x = -2147483648 + y = -2147483648 + r = x * y + if r != 0 { + t.Errorf("-2147483648 * -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x * y + if r != -2147483648 { + t.Errorf("-2147483648 * -2147483647 = %d, want -2147483648", r) + } + y = -1 + r = x * y + if r != -2147483648 { + t.Errorf("-2147483648 * -1 = %d, want -2147483648", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-2147483648 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -2147483648 { + t.Errorf("-2147483648 * 1 = %d, want -2147483648", r) + } + y = 2147483647 + r = x * y + if r != -2147483648 { + t.Errorf("-2147483648 * 2147483647 = %d, want -2147483648", r) + } + x = -2147483647 + y = -2147483648 + r = x * y + if r != -2147483648 { + t.Errorf("-2147483647 * -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x * y + if r != 1 { + t.Errorf("-2147483647 * -2147483647 = %d, want 1", r) + } + y = -1 + r = x * y + if r != 2147483647 { + t.Errorf("-2147483647 * -1 = %d, want 2147483647", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-2147483647 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -2147483647 { + t.Errorf("-2147483647 * 1 = %d, want -2147483647", r) + } + y = 2147483647 + r = x * y + if r != -1 { + t.Errorf("-2147483647 * 2147483647 = %d, want -1", r) + } + x = -1 + y = -2147483648 + r = x * y + if r != -2147483648 { + t.Errorf("-1 * -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x * y + if r != 2147483647 { + t.Errorf("-1 * -2147483647 = %d, want 2147483647", r) + } + y = -1 + r = x * y + if r != 1 { + t.Errorf("-1 * -1 = %d, want 1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -1 { + t.Errorf("-1 * 1 = %d, want -1", r) + } + y = 2147483647 + r = x * y + if r != -2147483647 { + t.Errorf("-1 * 2147483647 = %d, want -2147483647", r) + } + x = 0 + y = -2147483648 + r = x * y + if r != 0 { + t.Errorf("0 * -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x * y + if r != 0 { + t.Errorf("0 * -2147483647 = %d, want 0", r) + } + y = -1 + r = x * y + if r != 0 { + t.Errorf("0 * -1 = %d, want 0", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 2147483647 + r = x * y + if r != 0 { + t.Errorf("0 * 2147483647 = %d, want 0", r) + } + x = 1 + y = -2147483648 + r = x * y + if r != -2147483648 { + t.Errorf("1 * -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x * y + if r != -2147483647 { + t.Errorf("1 * -2147483647 = %d, want -2147483647", r) + } + y = -1 + r = x * y + if r != -1 { + t.Errorf("1 * -1 = %d, want -1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 2147483647 + r = x * y + if r != 2147483647 { + t.Errorf("1 * 2147483647 = %d, want 2147483647", r) + } + x = 2147483647 + y = -2147483648 + r = x * y + if r != -2147483648 { + t.Errorf("2147483647 * -2147483648 = %d, want -2147483648", r) + } + y = -2147483647 + r = x * y + if r != -1 { + t.Errorf("2147483647 * -2147483647 = %d, want -1", r) + } + y = -1 + r = x * y + if r != -2147483647 { + t.Errorf("2147483647 * -1 = %d, want -2147483647", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("2147483647 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 2147483647 { + t.Errorf("2147483647 * 1 = %d, want 2147483647", r) + } + y = 2147483647 + r = x * y + if r != 1 { + t.Errorf("2147483647 * 2147483647 = %d, want 1", r) + } +} +func TestConstFoldint32mod(t *testing.T) { + var x, y, r int32 + x = -2147483648 + y = -2147483648 + r = x % y + if r != 0 { + t.Errorf("-2147483648 % -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x % y + if r != -1 { + t.Errorf("-2147483648 % -2147483647 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-2147483648 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-2147483648 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != -1 { + t.Errorf("-2147483648 % 2147483647 = %d, want -1", r) + } + x = -2147483647 + y = -2147483648 + r = x % y + if r != -2147483647 { + t.Errorf("-2147483647 % -2147483648 = %d, want -2147483647", r) + } + y = -2147483647 + r = x % y + if r != 0 { + t.Errorf("-2147483647 % -2147483647 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-2147483647 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-2147483647 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != 0 { + t.Errorf("-2147483647 % 2147483647 = %d, want 0", r) + } + x = -1 + y = -2147483648 + r = x % y + if r != -1 { + t.Errorf("-1 % -2147483648 = %d, want -1", r) + } + y = -2147483647 + r = x % y + if r != -1 { + t.Errorf("-1 % -2147483647 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-1 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != -1 { + t.Errorf("-1 % 2147483647 = %d, want -1", r) + } + x = 0 + y = -2147483648 + r = x % y + if r != 0 { + t.Errorf("0 % -2147483648 = %d, want 0", r) + } + y = -2147483647 + r = x % y + if r != 0 { + t.Errorf("0 % -2147483647 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("0 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != 0 { + t.Errorf("0 % 2147483647 = %d, want 0", r) + } + x = 1 + y = -2147483648 + r = x % y + if r != 1 { + t.Errorf("1 % -2147483648 = %d, want 1", r) + } + y = -2147483647 + r = x % y + if r != 1 { + t.Errorf("1 % -2147483647 = %d, want 1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != 1 { + t.Errorf("1 % 2147483647 = %d, want 1", r) + } + x = 2147483647 + y = -2147483648 + r = x % y + if r != 2147483647 { + t.Errorf("2147483647 % -2147483648 = %d, want 2147483647", r) + } + y = -2147483647 + r = x % y + if r != 0 { + t.Errorf("2147483647 % -2147483647 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("2147483647 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("2147483647 % 1 = %d, want 0", r) + } + y = 2147483647 + r = x % y + if r != 0 { + t.Errorf("2147483647 % 2147483647 = %d, want 0", r) + } +} +func TestConstFolduint16add(t *testing.T) { + var x, y, r uint16 + x = 0 + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 65535 + r = x + y + if r != 65535 { + t.Errorf("0 + 65535 = %d, want 65535", r) + } + x = 1 + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 65535 + r = x + y + if r != 0 { + t.Errorf("1 + 65535 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x + y + if r != 65535 { + t.Errorf("65535 + 0 = %d, want 65535", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("65535 + 1 = %d, want 0", r) + } + y = 65535 + r = x + y + if r != 65534 { + t.Errorf("65535 + 65535 = %d, want 65534", r) + } +} +func TestConstFolduint16sub(t *testing.T) { + var x, y, r uint16 + x = 0 + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != 65535 { + t.Errorf("0 - 1 = %d, want 65535", r) + } + y = 65535 + r = x - y + if r != 1 { + t.Errorf("0 - 65535 = %d, want 1", r) + } + x = 1 + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 65535 + r = x - y + if r != 2 { + t.Errorf("1 - 65535 = %d, want 2", r) + } + x = 65535 + y = 0 + r = x - y + if r != 65535 { + t.Errorf("65535 - 0 = %d, want 65535", r) + } + y = 1 + r = x - y + if r != 65534 { + t.Errorf("65535 - 1 = %d, want 65534", r) + } + y = 65535 + r = x - y + if r != 0 { + t.Errorf("65535 - 65535 = %d, want 0", r) + } +} +func TestConstFolduint16div(t *testing.T) { + var x, y, r uint16 + x = 0 + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 65535 + r = x / y + if r != 0 { + t.Errorf("0 / 65535 = %d, want 0", r) + } + x = 1 + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 65535 + r = x / y + if r != 0 { + t.Errorf("1 / 65535 = %d, want 0", r) + } + x = 65535 + y = 1 + r = x / y + if r != 65535 { + t.Errorf("65535 / 1 = %d, want 65535", r) + } + y = 65535 + r = x / y + if r != 1 { + t.Errorf("65535 / 65535 = %d, want 1", r) + } +} +func TestConstFolduint16mul(t *testing.T) { + var x, y, r uint16 + x = 0 + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 65535 + r = x * y + if r != 0 { + t.Errorf("0 * 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 65535 + r = x * y + if r != 65535 { + t.Errorf("1 * 65535 = %d, want 65535", r) + } + x = 65535 + y = 0 + r = x * y + if r != 0 { + t.Errorf("65535 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 65535 { + t.Errorf("65535 * 1 = %d, want 65535", r) + } + y = 65535 + r = x * y + if r != 1 { + t.Errorf("65535 * 65535 = %d, want 1", r) + } +} +func TestConstFolduint16mod(t *testing.T) { + var x, y, r uint16 + x = 0 + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 65535 + r = x % y + if r != 0 { + t.Errorf("0 % 65535 = %d, want 0", r) + } + x = 1 + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 65535 + r = x % y + if r != 1 { + t.Errorf("1 % 65535 = %d, want 1", r) + } + x = 65535 + y = 1 + r = x % y + if r != 0 { + t.Errorf("65535 % 1 = %d, want 0", r) + } + y = 65535 + r = x % y + if r != 0 { + t.Errorf("65535 % 65535 = %d, want 0", r) + } +} +func TestConstFoldint16add(t *testing.T) { + var x, y, r int16 + x = -32768 + y = -32768 + r = x + y + if r != 0 { + t.Errorf("-32768 + -32768 = %d, want 0", r) + } + y = -32767 + r = x + y + if r != 1 { + t.Errorf("-32768 + -32767 = %d, want 1", r) + } + y = -1 + r = x + y + if r != 32767 { + t.Errorf("-32768 + -1 = %d, want 32767", r) + } + y = 0 + r = x + y + if r != -32768 { + t.Errorf("-32768 + 0 = %d, want -32768", r) + } + y = 1 + r = x + y + if r != -32767 { + t.Errorf("-32768 + 1 = %d, want -32767", r) + } + y = 32766 + r = x + y + if r != -2 { + t.Errorf("-32768 + 32766 = %d, want -2", r) + } + y = 32767 + r = x + y + if r != -1 { + t.Errorf("-32768 + 32767 = %d, want -1", r) + } + x = -32767 + y = -32768 + r = x + y + if r != 1 { + t.Errorf("-32767 + -32768 = %d, want 1", r) + } + y = -32767 + r = x + y + if r != 2 { + t.Errorf("-32767 + -32767 = %d, want 2", r) + } + y = -1 + r = x + y + if r != -32768 { + t.Errorf("-32767 + -1 = %d, want -32768", r) + } + y = 0 + r = x + y + if r != -32767 { + t.Errorf("-32767 + 0 = %d, want -32767", r) + } + y = 1 + r = x + y + if r != -32766 { + t.Errorf("-32767 + 1 = %d, want -32766", r) + } + y = 32766 + r = x + y + if r != -1 { + t.Errorf("-32767 + 32766 = %d, want -1", r) + } + y = 32767 + r = x + y + if r != 0 { + t.Errorf("-32767 + 32767 = %d, want 0", r) + } + x = -1 + y = -32768 + r = x + y + if r != 32767 { + t.Errorf("-1 + -32768 = %d, want 32767", r) + } + y = -32767 + r = x + y + if r != -32768 { + t.Errorf("-1 + -32767 = %d, want -32768", r) + } + y = -1 + r = x + y + if r != -2 { + t.Errorf("-1 + -1 = %d, want -2", r) + } + y = 0 + r = x + y + if r != -1 { + t.Errorf("-1 + 0 = %d, want -1", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("-1 + 1 = %d, want 0", r) + } + y = 32766 + r = x + y + if r != 32765 { + t.Errorf("-1 + 32766 = %d, want 32765", r) + } + y = 32767 + r = x + y + if r != 32766 { + t.Errorf("-1 + 32767 = %d, want 32766", r) + } + x = 0 + y = -32768 + r = x + y + if r != -32768 { + t.Errorf("0 + -32768 = %d, want -32768", r) + } + y = -32767 + r = x + y + if r != -32767 { + t.Errorf("0 + -32767 = %d, want -32767", r) + } + y = -1 + r = x + y + if r != -1 { + t.Errorf("0 + -1 = %d, want -1", r) + } + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 32766 + r = x + y + if r != 32766 { + t.Errorf("0 + 32766 = %d, want 32766", r) + } + y = 32767 + r = x + y + if r != 32767 { + t.Errorf("0 + 32767 = %d, want 32767", r) + } + x = 1 + y = -32768 + r = x + y + if r != -32767 { + t.Errorf("1 + -32768 = %d, want -32767", r) + } + y = -32767 + r = x + y + if r != -32766 { + t.Errorf("1 + -32767 = %d, want -32766", r) + } + y = -1 + r = x + y + if r != 0 { + t.Errorf("1 + -1 = %d, want 0", r) + } + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 32766 + r = x + y + if r != 32767 { + t.Errorf("1 + 32766 = %d, want 32767", r) + } + y = 32767 + r = x + y + if r != -32768 { + t.Errorf("1 + 32767 = %d, want -32768", r) + } + x = 32766 + y = -32768 + r = x + y + if r != -2 { + t.Errorf("32766 + -32768 = %d, want -2", r) + } + y = -32767 + r = x + y + if r != -1 { + t.Errorf("32766 + -32767 = %d, want -1", r) + } + y = -1 + r = x + y + if r != 32765 { + t.Errorf("32766 + -1 = %d, want 32765", r) + } + y = 0 + r = x + y + if r != 32766 { + t.Errorf("32766 + 0 = %d, want 32766", r) + } + y = 1 + r = x + y + if r != 32767 { + t.Errorf("32766 + 1 = %d, want 32767", r) + } + y = 32766 + r = x + y + if r != -4 { + t.Errorf("32766 + 32766 = %d, want -4", r) + } + y = 32767 + r = x + y + if r != -3 { + t.Errorf("32766 + 32767 = %d, want -3", r) + } + x = 32767 + y = -32768 + r = x + y + if r != -1 { + t.Errorf("32767 + -32768 = %d, want -1", r) + } + y = -32767 + r = x + y + if r != 0 { + t.Errorf("32767 + -32767 = %d, want 0", r) + } + y = -1 + r = x + y + if r != 32766 { + t.Errorf("32767 + -1 = %d, want 32766", r) + } + y = 0 + r = x + y + if r != 32767 { + t.Errorf("32767 + 0 = %d, want 32767", r) + } + y = 1 + r = x + y + if r != -32768 { + t.Errorf("32767 + 1 = %d, want -32768", r) + } + y = 32766 + r = x + y + if r != -3 { + t.Errorf("32767 + 32766 = %d, want -3", r) + } + y = 32767 + r = x + y + if r != -2 { + t.Errorf("32767 + 32767 = %d, want -2", r) + } +} +func TestConstFoldint16sub(t *testing.T) { + var x, y, r int16 + x = -32768 + y = -32768 + r = x - y + if r != 0 { + t.Errorf("-32768 - -32768 = %d, want 0", r) + } + y = -32767 + r = x - y + if r != -1 { + t.Errorf("-32768 - -32767 = %d, want -1", r) + } + y = -1 + r = x - y + if r != -32767 { + t.Errorf("-32768 - -1 = %d, want -32767", r) + } + y = 0 + r = x - y + if r != -32768 { + t.Errorf("-32768 - 0 = %d, want -32768", r) + } + y = 1 + r = x - y + if r != 32767 { + t.Errorf("-32768 - 1 = %d, want 32767", r) + } + y = 32766 + r = x - y + if r != 2 { + t.Errorf("-32768 - 32766 = %d, want 2", r) + } + y = 32767 + r = x - y + if r != 1 { + t.Errorf("-32768 - 32767 = %d, want 1", r) + } + x = -32767 + y = -32768 + r = x - y + if r != 1 { + t.Errorf("-32767 - -32768 = %d, want 1", r) + } + y = -32767 + r = x - y + if r != 0 { + t.Errorf("-32767 - -32767 = %d, want 0", r) + } + y = -1 + r = x - y + if r != -32766 { + t.Errorf("-32767 - -1 = %d, want -32766", r) + } + y = 0 + r = x - y + if r != -32767 { + t.Errorf("-32767 - 0 = %d, want -32767", r) + } + y = 1 + r = x - y + if r != -32768 { + t.Errorf("-32767 - 1 = %d, want -32768", r) + } + y = 32766 + r = x - y + if r != 3 { + t.Errorf("-32767 - 32766 = %d, want 3", r) + } + y = 32767 + r = x - y + if r != 2 { + t.Errorf("-32767 - 32767 = %d, want 2", r) + } + x = -1 + y = -32768 + r = x - y + if r != 32767 { + t.Errorf("-1 - -32768 = %d, want 32767", r) + } + y = -32767 + r = x - y + if r != 32766 { + t.Errorf("-1 - -32767 = %d, want 32766", r) + } + y = -1 + r = x - y + if r != 0 { + t.Errorf("-1 - -1 = %d, want 0", r) + } + y = 0 + r = x - y + if r != -1 { + t.Errorf("-1 - 0 = %d, want -1", r) + } + y = 1 + r = x - y + if r != -2 { + t.Errorf("-1 - 1 = %d, want -2", r) + } + y = 32766 + r = x - y + if r != -32767 { + t.Errorf("-1 - 32766 = %d, want -32767", r) + } + y = 32767 + r = x - y + if r != -32768 { + t.Errorf("-1 - 32767 = %d, want -32768", r) + } + x = 0 + y = -32768 + r = x - y + if r != -32768 { + t.Errorf("0 - -32768 = %d, want -32768", r) + } + y = -32767 + r = x - y + if r != 32767 { + t.Errorf("0 - -32767 = %d, want 32767", r) + } + y = -1 + r = x - y + if r != 1 { + t.Errorf("0 - -1 = %d, want 1", r) + } + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != -1 { + t.Errorf("0 - 1 = %d, want -1", r) + } + y = 32766 + r = x - y + if r != -32766 { + t.Errorf("0 - 32766 = %d, want -32766", r) + } + y = 32767 + r = x - y + if r != -32767 { + t.Errorf("0 - 32767 = %d, want -32767", r) + } + x = 1 + y = -32768 + r = x - y + if r != -32767 { + t.Errorf("1 - -32768 = %d, want -32767", r) + } + y = -32767 + r = x - y + if r != -32768 { + t.Errorf("1 - -32767 = %d, want -32768", r) + } + y = -1 + r = x - y + if r != 2 { + t.Errorf("1 - -1 = %d, want 2", r) + } + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 32766 + r = x - y + if r != -32765 { + t.Errorf("1 - 32766 = %d, want -32765", r) + } + y = 32767 + r = x - y + if r != -32766 { + t.Errorf("1 - 32767 = %d, want -32766", r) + } + x = 32766 + y = -32768 + r = x - y + if r != -2 { + t.Errorf("32766 - -32768 = %d, want -2", r) + } + y = -32767 + r = x - y + if r != -3 { + t.Errorf("32766 - -32767 = %d, want -3", r) + } + y = -1 + r = x - y + if r != 32767 { + t.Errorf("32766 - -1 = %d, want 32767", r) + } + y = 0 + r = x - y + if r != 32766 { + t.Errorf("32766 - 0 = %d, want 32766", r) + } + y = 1 + r = x - y + if r != 32765 { + t.Errorf("32766 - 1 = %d, want 32765", r) + } + y = 32766 + r = x - y + if r != 0 { + t.Errorf("32766 - 32766 = %d, want 0", r) + } + y = 32767 + r = x - y + if r != -1 { + t.Errorf("32766 - 32767 = %d, want -1", r) + } + x = 32767 + y = -32768 + r = x - y + if r != -1 { + t.Errorf("32767 - -32768 = %d, want -1", r) + } + y = -32767 + r = x - y + if r != -2 { + t.Errorf("32767 - -32767 = %d, want -2", r) + } + y = -1 + r = x - y + if r != -32768 { + t.Errorf("32767 - -1 = %d, want -32768", r) + } + y = 0 + r = x - y + if r != 32767 { + t.Errorf("32767 - 0 = %d, want 32767", r) + } + y = 1 + r = x - y + if r != 32766 { + t.Errorf("32767 - 1 = %d, want 32766", r) + } + y = 32766 + r = x - y + if r != 1 { + t.Errorf("32767 - 32766 = %d, want 1", r) + } + y = 32767 + r = x - y + if r != 0 { + t.Errorf("32767 - 32767 = %d, want 0", r) + } +} +func TestConstFoldint16div(t *testing.T) { + var x, y, r int16 + x = -32768 + y = -32768 + r = x / y + if r != 1 { + t.Errorf("-32768 / -32768 = %d, want 1", r) + } + y = -32767 + r = x / y + if r != 1 { + t.Errorf("-32768 / -32767 = %d, want 1", r) + } + y = -1 + r = x / y + if r != -32768 { + t.Errorf("-32768 / -1 = %d, want -32768", r) + } + y = 1 + r = x / y + if r != -32768 { + t.Errorf("-32768 / 1 = %d, want -32768", r) + } + y = 32766 + r = x / y + if r != -1 { + t.Errorf("-32768 / 32766 = %d, want -1", r) + } + y = 32767 + r = x / y + if r != -1 { + t.Errorf("-32768 / 32767 = %d, want -1", r) + } + x = -32767 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("-32767 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != 1 { + t.Errorf("-32767 / -32767 = %d, want 1", r) + } + y = -1 + r = x / y + if r != 32767 { + t.Errorf("-32767 / -1 = %d, want 32767", r) + } + y = 1 + r = x / y + if r != -32767 { + t.Errorf("-32767 / 1 = %d, want -32767", r) + } + y = 32766 + r = x / y + if r != -1 { + t.Errorf("-32767 / 32766 = %d, want -1", r) + } + y = 32767 + r = x / y + if r != -1 { + t.Errorf("-32767 / 32767 = %d, want -1", r) + } + x = -1 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("-1 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != 0 { + t.Errorf("-1 / -32767 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 1 { + t.Errorf("-1 / -1 = %d, want 1", r) + } + y = 1 + r = x / y + if r != -1 { + t.Errorf("-1 / 1 = %d, want -1", r) + } + y = 32766 + r = x / y + if r != 0 { + t.Errorf("-1 / 32766 = %d, want 0", r) + } + y = 32767 + r = x / y + if r != 0 { + t.Errorf("-1 / 32767 = %d, want 0", r) + } + x = 0 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("0 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != 0 { + t.Errorf("0 / -32767 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 0 { + t.Errorf("0 / -1 = %d, want 0", r) + } + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 32766 + r = x / y + if r != 0 { + t.Errorf("0 / 32766 = %d, want 0", r) + } + y = 32767 + r = x / y + if r != 0 { + t.Errorf("0 / 32767 = %d, want 0", r) + } + x = 1 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("1 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != 0 { + t.Errorf("1 / -32767 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -1 { + t.Errorf("1 / -1 = %d, want -1", r) + } + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 32766 + r = x / y + if r != 0 { + t.Errorf("1 / 32766 = %d, want 0", r) + } + y = 32767 + r = x / y + if r != 0 { + t.Errorf("1 / 32767 = %d, want 0", r) + } + x = 32766 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("32766 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != 0 { + t.Errorf("32766 / -32767 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -32766 { + t.Errorf("32766 / -1 = %d, want -32766", r) + } + y = 1 + r = x / y + if r != 32766 { + t.Errorf("32766 / 1 = %d, want 32766", r) + } + y = 32766 + r = x / y + if r != 1 { + t.Errorf("32766 / 32766 = %d, want 1", r) + } + y = 32767 + r = x / y + if r != 0 { + t.Errorf("32766 / 32767 = %d, want 0", r) + } + x = 32767 + y = -32768 + r = x / y + if r != 0 { + t.Errorf("32767 / -32768 = %d, want 0", r) + } + y = -32767 + r = x / y + if r != -1 { + t.Errorf("32767 / -32767 = %d, want -1", r) + } + y = -1 + r = x / y + if r != -32767 { + t.Errorf("32767 / -1 = %d, want -32767", r) + } + y = 1 + r = x / y + if r != 32767 { + t.Errorf("32767 / 1 = %d, want 32767", r) + } + y = 32766 + r = x / y + if r != 1 { + t.Errorf("32767 / 32766 = %d, want 1", r) + } + y = 32767 + r = x / y + if r != 1 { + t.Errorf("32767 / 32767 = %d, want 1", r) + } +} +func TestConstFoldint16mul(t *testing.T) { + var x, y, r int16 + x = -32768 + y = -32768 + r = x * y + if r != 0 { + t.Errorf("-32768 * -32768 = %d, want 0", r) + } + y = -32767 + r = x * y + if r != -32768 { + t.Errorf("-32768 * -32767 = %d, want -32768", r) + } + y = -1 + r = x * y + if r != -32768 { + t.Errorf("-32768 * -1 = %d, want -32768", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-32768 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -32768 { + t.Errorf("-32768 * 1 = %d, want -32768", r) + } + y = 32766 + r = x * y + if r != 0 { + t.Errorf("-32768 * 32766 = %d, want 0", r) + } + y = 32767 + r = x * y + if r != -32768 { + t.Errorf("-32768 * 32767 = %d, want -32768", r) + } + x = -32767 + y = -32768 + r = x * y + if r != -32768 { + t.Errorf("-32767 * -32768 = %d, want -32768", r) + } + y = -32767 + r = x * y + if r != 1 { + t.Errorf("-32767 * -32767 = %d, want 1", r) + } + y = -1 + r = x * y + if r != 32767 { + t.Errorf("-32767 * -1 = %d, want 32767", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-32767 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -32767 { + t.Errorf("-32767 * 1 = %d, want -32767", r) + } + y = 32766 + r = x * y + if r != 32766 { + t.Errorf("-32767 * 32766 = %d, want 32766", r) + } + y = 32767 + r = x * y + if r != -1 { + t.Errorf("-32767 * 32767 = %d, want -1", r) + } + x = -1 + y = -32768 + r = x * y + if r != -32768 { + t.Errorf("-1 * -32768 = %d, want -32768", r) + } + y = -32767 + r = x * y + if r != 32767 { + t.Errorf("-1 * -32767 = %d, want 32767", r) + } + y = -1 + r = x * y + if r != 1 { + t.Errorf("-1 * -1 = %d, want 1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -1 { + t.Errorf("-1 * 1 = %d, want -1", r) + } + y = 32766 + r = x * y + if r != -32766 { + t.Errorf("-1 * 32766 = %d, want -32766", r) + } + y = 32767 + r = x * y + if r != -32767 { + t.Errorf("-1 * 32767 = %d, want -32767", r) + } + x = 0 + y = -32768 + r = x * y + if r != 0 { + t.Errorf("0 * -32768 = %d, want 0", r) + } + y = -32767 + r = x * y + if r != 0 { + t.Errorf("0 * -32767 = %d, want 0", r) + } + y = -1 + r = x * y + if r != 0 { + t.Errorf("0 * -1 = %d, want 0", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 32766 + r = x * y + if r != 0 { + t.Errorf("0 * 32766 = %d, want 0", r) + } + y = 32767 + r = x * y + if r != 0 { + t.Errorf("0 * 32767 = %d, want 0", r) + } + x = 1 + y = -32768 + r = x * y + if r != -32768 { + t.Errorf("1 * -32768 = %d, want -32768", r) + } + y = -32767 + r = x * y + if r != -32767 { + t.Errorf("1 * -32767 = %d, want -32767", r) + } + y = -1 + r = x * y + if r != -1 { + t.Errorf("1 * -1 = %d, want -1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 32766 + r = x * y + if r != 32766 { + t.Errorf("1 * 32766 = %d, want 32766", r) + } + y = 32767 + r = x * y + if r != 32767 { + t.Errorf("1 * 32767 = %d, want 32767", r) + } + x = 32766 + y = -32768 + r = x * y + if r != 0 { + t.Errorf("32766 * -32768 = %d, want 0", r) + } + y = -32767 + r = x * y + if r != 32766 { + t.Errorf("32766 * -32767 = %d, want 32766", r) + } + y = -1 + r = x * y + if r != -32766 { + t.Errorf("32766 * -1 = %d, want -32766", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("32766 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 32766 { + t.Errorf("32766 * 1 = %d, want 32766", r) + } + y = 32766 + r = x * y + if r != 4 { + t.Errorf("32766 * 32766 = %d, want 4", r) + } + y = 32767 + r = x * y + if r != -32766 { + t.Errorf("32766 * 32767 = %d, want -32766", r) + } + x = 32767 + y = -32768 + r = x * y + if r != -32768 { + t.Errorf("32767 * -32768 = %d, want -32768", r) + } + y = -32767 + r = x * y + if r != -1 { + t.Errorf("32767 * -32767 = %d, want -1", r) + } + y = -1 + r = x * y + if r != -32767 { + t.Errorf("32767 * -1 = %d, want -32767", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("32767 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 32767 { + t.Errorf("32767 * 1 = %d, want 32767", r) + } + y = 32766 + r = x * y + if r != -32766 { + t.Errorf("32767 * 32766 = %d, want -32766", r) + } + y = 32767 + r = x * y + if r != 1 { + t.Errorf("32767 * 32767 = %d, want 1", r) + } +} +func TestConstFoldint16mod(t *testing.T) { + var x, y, r int16 + x = -32768 + y = -32768 + r = x % y + if r != 0 { + t.Errorf("-32768 % -32768 = %d, want 0", r) + } + y = -32767 + r = x % y + if r != -1 { + t.Errorf("-32768 % -32767 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-32768 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-32768 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != -2 { + t.Errorf("-32768 % 32766 = %d, want -2", r) + } + y = 32767 + r = x % y + if r != -1 { + t.Errorf("-32768 % 32767 = %d, want -1", r) + } + x = -32767 + y = -32768 + r = x % y + if r != -32767 { + t.Errorf("-32767 % -32768 = %d, want -32767", r) + } + y = -32767 + r = x % y + if r != 0 { + t.Errorf("-32767 % -32767 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-32767 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-32767 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != -1 { + t.Errorf("-32767 % 32766 = %d, want -1", r) + } + y = 32767 + r = x % y + if r != 0 { + t.Errorf("-32767 % 32767 = %d, want 0", r) + } + x = -1 + y = -32768 + r = x % y + if r != -1 { + t.Errorf("-1 % -32768 = %d, want -1", r) + } + y = -32767 + r = x % y + if r != -1 { + t.Errorf("-1 % -32767 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-1 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != -1 { + t.Errorf("-1 % 32766 = %d, want -1", r) + } + y = 32767 + r = x % y + if r != -1 { + t.Errorf("-1 % 32767 = %d, want -1", r) + } + x = 0 + y = -32768 + r = x % y + if r != 0 { + t.Errorf("0 % -32768 = %d, want 0", r) + } + y = -32767 + r = x % y + if r != 0 { + t.Errorf("0 % -32767 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("0 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != 0 { + t.Errorf("0 % 32766 = %d, want 0", r) + } + y = 32767 + r = x % y + if r != 0 { + t.Errorf("0 % 32767 = %d, want 0", r) + } + x = 1 + y = -32768 + r = x % y + if r != 1 { + t.Errorf("1 % -32768 = %d, want 1", r) + } + y = -32767 + r = x % y + if r != 1 { + t.Errorf("1 % -32767 = %d, want 1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != 1 { + t.Errorf("1 % 32766 = %d, want 1", r) + } + y = 32767 + r = x % y + if r != 1 { + t.Errorf("1 % 32767 = %d, want 1", r) + } + x = 32766 + y = -32768 + r = x % y + if r != 32766 { + t.Errorf("32766 % -32768 = %d, want 32766", r) + } + y = -32767 + r = x % y + if r != 32766 { + t.Errorf("32766 % -32767 = %d, want 32766", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("32766 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("32766 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != 0 { + t.Errorf("32766 % 32766 = %d, want 0", r) + } + y = 32767 + r = x % y + if r != 32766 { + t.Errorf("32766 % 32767 = %d, want 32766", r) + } + x = 32767 + y = -32768 + r = x % y + if r != 32767 { + t.Errorf("32767 % -32768 = %d, want 32767", r) + } + y = -32767 + r = x % y + if r != 0 { + t.Errorf("32767 % -32767 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("32767 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("32767 % 1 = %d, want 0", r) + } + y = 32766 + r = x % y + if r != 1 { + t.Errorf("32767 % 32766 = %d, want 1", r) + } + y = 32767 + r = x % y + if r != 0 { + t.Errorf("32767 % 32767 = %d, want 0", r) + } +} +func TestConstFolduint8add(t *testing.T) { + var x, y, r uint8 + x = 0 + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 255 + r = x + y + if r != 255 { + t.Errorf("0 + 255 = %d, want 255", r) + } + x = 1 + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 255 + r = x + y + if r != 0 { + t.Errorf("1 + 255 = %d, want 0", r) + } + x = 255 + y = 0 + r = x + y + if r != 255 { + t.Errorf("255 + 0 = %d, want 255", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("255 + 1 = %d, want 0", r) + } + y = 255 + r = x + y + if r != 254 { + t.Errorf("255 + 255 = %d, want 254", r) + } +} +func TestConstFolduint8sub(t *testing.T) { + var x, y, r uint8 + x = 0 + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != 255 { + t.Errorf("0 - 1 = %d, want 255", r) + } + y = 255 + r = x - y + if r != 1 { + t.Errorf("0 - 255 = %d, want 1", r) + } + x = 1 + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 255 + r = x - y + if r != 2 { + t.Errorf("1 - 255 = %d, want 2", r) + } + x = 255 + y = 0 + r = x - y + if r != 255 { + t.Errorf("255 - 0 = %d, want 255", r) + } + y = 1 + r = x - y + if r != 254 { + t.Errorf("255 - 1 = %d, want 254", r) + } + y = 255 + r = x - y + if r != 0 { + t.Errorf("255 - 255 = %d, want 0", r) + } +} +func TestConstFolduint8div(t *testing.T) { + var x, y, r uint8 + x = 0 + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 255 + r = x / y + if r != 0 { + t.Errorf("0 / 255 = %d, want 0", r) + } + x = 1 + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 255 + r = x / y + if r != 0 { + t.Errorf("1 / 255 = %d, want 0", r) + } + x = 255 + y = 1 + r = x / y + if r != 255 { + t.Errorf("255 / 1 = %d, want 255", r) + } + y = 255 + r = x / y + if r != 1 { + t.Errorf("255 / 255 = %d, want 1", r) + } +} +func TestConstFolduint8mul(t *testing.T) { + var x, y, r uint8 + x = 0 + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 255 + r = x * y + if r != 0 { + t.Errorf("0 * 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 255 + r = x * y + if r != 255 { + t.Errorf("1 * 255 = %d, want 255", r) + } + x = 255 + y = 0 + r = x * y + if r != 0 { + t.Errorf("255 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 255 { + t.Errorf("255 * 1 = %d, want 255", r) + } + y = 255 + r = x * y + if r != 1 { + t.Errorf("255 * 255 = %d, want 1", r) + } +} +func TestConstFolduint8mod(t *testing.T) { + var x, y, r uint8 + x = 0 + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 255 + r = x % y + if r != 0 { + t.Errorf("0 % 255 = %d, want 0", r) + } + x = 1 + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 255 + r = x % y + if r != 1 { + t.Errorf("1 % 255 = %d, want 1", r) + } + x = 255 + y = 1 + r = x % y + if r != 0 { + t.Errorf("255 % 1 = %d, want 0", r) + } + y = 255 + r = x % y + if r != 0 { + t.Errorf("255 % 255 = %d, want 0", r) + } +} +func TestConstFoldint8add(t *testing.T) { + var x, y, r int8 + x = -128 + y = -128 + r = x + y + if r != 0 { + t.Errorf("-128 + -128 = %d, want 0", r) + } + y = -127 + r = x + y + if r != 1 { + t.Errorf("-128 + -127 = %d, want 1", r) + } + y = -1 + r = x + y + if r != 127 { + t.Errorf("-128 + -1 = %d, want 127", r) + } + y = 0 + r = x + y + if r != -128 { + t.Errorf("-128 + 0 = %d, want -128", r) + } + y = 1 + r = x + y + if r != -127 { + t.Errorf("-128 + 1 = %d, want -127", r) + } + y = 126 + r = x + y + if r != -2 { + t.Errorf("-128 + 126 = %d, want -2", r) + } + y = 127 + r = x + y + if r != -1 { + t.Errorf("-128 + 127 = %d, want -1", r) + } + x = -127 + y = -128 + r = x + y + if r != 1 { + t.Errorf("-127 + -128 = %d, want 1", r) + } + y = -127 + r = x + y + if r != 2 { + t.Errorf("-127 + -127 = %d, want 2", r) + } + y = -1 + r = x + y + if r != -128 { + t.Errorf("-127 + -1 = %d, want -128", r) + } + y = 0 + r = x + y + if r != -127 { + t.Errorf("-127 + 0 = %d, want -127", r) + } + y = 1 + r = x + y + if r != -126 { + t.Errorf("-127 + 1 = %d, want -126", r) + } + y = 126 + r = x + y + if r != -1 { + t.Errorf("-127 + 126 = %d, want -1", r) + } + y = 127 + r = x + y + if r != 0 { + t.Errorf("-127 + 127 = %d, want 0", r) + } + x = -1 + y = -128 + r = x + y + if r != 127 { + t.Errorf("-1 + -128 = %d, want 127", r) + } + y = -127 + r = x + y + if r != -128 { + t.Errorf("-1 + -127 = %d, want -128", r) + } + y = -1 + r = x + y + if r != -2 { + t.Errorf("-1 + -1 = %d, want -2", r) + } + y = 0 + r = x + y + if r != -1 { + t.Errorf("-1 + 0 = %d, want -1", r) + } + y = 1 + r = x + y + if r != 0 { + t.Errorf("-1 + 1 = %d, want 0", r) + } + y = 126 + r = x + y + if r != 125 { + t.Errorf("-1 + 126 = %d, want 125", r) + } + y = 127 + r = x + y + if r != 126 { + t.Errorf("-1 + 127 = %d, want 126", r) + } + x = 0 + y = -128 + r = x + y + if r != -128 { + t.Errorf("0 + -128 = %d, want -128", r) + } + y = -127 + r = x + y + if r != -127 { + t.Errorf("0 + -127 = %d, want -127", r) + } + y = -1 + r = x + y + if r != -1 { + t.Errorf("0 + -1 = %d, want -1", r) + } + y = 0 + r = x + y + if r != 0 { + t.Errorf("0 + 0 = %d, want 0", r) + } + y = 1 + r = x + y + if r != 1 { + t.Errorf("0 + 1 = %d, want 1", r) + } + y = 126 + r = x + y + if r != 126 { + t.Errorf("0 + 126 = %d, want 126", r) + } + y = 127 + r = x + y + if r != 127 { + t.Errorf("0 + 127 = %d, want 127", r) + } + x = 1 + y = -128 + r = x + y + if r != -127 { + t.Errorf("1 + -128 = %d, want -127", r) + } + y = -127 + r = x + y + if r != -126 { + t.Errorf("1 + -127 = %d, want -126", r) + } + y = -1 + r = x + y + if r != 0 { + t.Errorf("1 + -1 = %d, want 0", r) + } + y = 0 + r = x + y + if r != 1 { + t.Errorf("1 + 0 = %d, want 1", r) + } + y = 1 + r = x + y + if r != 2 { + t.Errorf("1 + 1 = %d, want 2", r) + } + y = 126 + r = x + y + if r != 127 { + t.Errorf("1 + 126 = %d, want 127", r) + } + y = 127 + r = x + y + if r != -128 { + t.Errorf("1 + 127 = %d, want -128", r) + } + x = 126 + y = -128 + r = x + y + if r != -2 { + t.Errorf("126 + -128 = %d, want -2", r) + } + y = -127 + r = x + y + if r != -1 { + t.Errorf("126 + -127 = %d, want -1", r) + } + y = -1 + r = x + y + if r != 125 { + t.Errorf("126 + -1 = %d, want 125", r) + } + y = 0 + r = x + y + if r != 126 { + t.Errorf("126 + 0 = %d, want 126", r) + } + y = 1 + r = x + y + if r != 127 { + t.Errorf("126 + 1 = %d, want 127", r) + } + y = 126 + r = x + y + if r != -4 { + t.Errorf("126 + 126 = %d, want -4", r) + } + y = 127 + r = x + y + if r != -3 { + t.Errorf("126 + 127 = %d, want -3", r) + } + x = 127 + y = -128 + r = x + y + if r != -1 { + t.Errorf("127 + -128 = %d, want -1", r) + } + y = -127 + r = x + y + if r != 0 { + t.Errorf("127 + -127 = %d, want 0", r) + } + y = -1 + r = x + y + if r != 126 { + t.Errorf("127 + -1 = %d, want 126", r) + } + y = 0 + r = x + y + if r != 127 { + t.Errorf("127 + 0 = %d, want 127", r) + } + y = 1 + r = x + y + if r != -128 { + t.Errorf("127 + 1 = %d, want -128", r) + } + y = 126 + r = x + y + if r != -3 { + t.Errorf("127 + 126 = %d, want -3", r) + } + y = 127 + r = x + y + if r != -2 { + t.Errorf("127 + 127 = %d, want -2", r) + } +} +func TestConstFoldint8sub(t *testing.T) { + var x, y, r int8 + x = -128 + y = -128 + r = x - y + if r != 0 { + t.Errorf("-128 - -128 = %d, want 0", r) + } + y = -127 + r = x - y + if r != -1 { + t.Errorf("-128 - -127 = %d, want -1", r) + } + y = -1 + r = x - y + if r != -127 { + t.Errorf("-128 - -1 = %d, want -127", r) + } + y = 0 + r = x - y + if r != -128 { + t.Errorf("-128 - 0 = %d, want -128", r) + } + y = 1 + r = x - y + if r != 127 { + t.Errorf("-128 - 1 = %d, want 127", r) + } + y = 126 + r = x - y + if r != 2 { + t.Errorf("-128 - 126 = %d, want 2", r) + } + y = 127 + r = x - y + if r != 1 { + t.Errorf("-128 - 127 = %d, want 1", r) + } + x = -127 + y = -128 + r = x - y + if r != 1 { + t.Errorf("-127 - -128 = %d, want 1", r) + } + y = -127 + r = x - y + if r != 0 { + t.Errorf("-127 - -127 = %d, want 0", r) + } + y = -1 + r = x - y + if r != -126 { + t.Errorf("-127 - -1 = %d, want -126", r) + } + y = 0 + r = x - y + if r != -127 { + t.Errorf("-127 - 0 = %d, want -127", r) + } + y = 1 + r = x - y + if r != -128 { + t.Errorf("-127 - 1 = %d, want -128", r) + } + y = 126 + r = x - y + if r != 3 { + t.Errorf("-127 - 126 = %d, want 3", r) + } + y = 127 + r = x - y + if r != 2 { + t.Errorf("-127 - 127 = %d, want 2", r) + } + x = -1 + y = -128 + r = x - y + if r != 127 { + t.Errorf("-1 - -128 = %d, want 127", r) + } + y = -127 + r = x - y + if r != 126 { + t.Errorf("-1 - -127 = %d, want 126", r) + } + y = -1 + r = x - y + if r != 0 { + t.Errorf("-1 - -1 = %d, want 0", r) + } + y = 0 + r = x - y + if r != -1 { + t.Errorf("-1 - 0 = %d, want -1", r) + } + y = 1 + r = x - y + if r != -2 { + t.Errorf("-1 - 1 = %d, want -2", r) + } + y = 126 + r = x - y + if r != -127 { + t.Errorf("-1 - 126 = %d, want -127", r) + } + y = 127 + r = x - y + if r != -128 { + t.Errorf("-1 - 127 = %d, want -128", r) + } + x = 0 + y = -128 + r = x - y + if r != -128 { + t.Errorf("0 - -128 = %d, want -128", r) + } + y = -127 + r = x - y + if r != 127 { + t.Errorf("0 - -127 = %d, want 127", r) + } + y = -1 + r = x - y + if r != 1 { + t.Errorf("0 - -1 = %d, want 1", r) + } + y = 0 + r = x - y + if r != 0 { + t.Errorf("0 - 0 = %d, want 0", r) + } + y = 1 + r = x - y + if r != -1 { + t.Errorf("0 - 1 = %d, want -1", r) + } + y = 126 + r = x - y + if r != -126 { + t.Errorf("0 - 126 = %d, want -126", r) + } + y = 127 + r = x - y + if r != -127 { + t.Errorf("0 - 127 = %d, want -127", r) + } + x = 1 + y = -128 + r = x - y + if r != -127 { + t.Errorf("1 - -128 = %d, want -127", r) + } + y = -127 + r = x - y + if r != -128 { + t.Errorf("1 - -127 = %d, want -128", r) + } + y = -1 + r = x - y + if r != 2 { + t.Errorf("1 - -1 = %d, want 2", r) + } + y = 0 + r = x - y + if r != 1 { + t.Errorf("1 - 0 = %d, want 1", r) + } + y = 1 + r = x - y + if r != 0 { + t.Errorf("1 - 1 = %d, want 0", r) + } + y = 126 + r = x - y + if r != -125 { + t.Errorf("1 - 126 = %d, want -125", r) + } + y = 127 + r = x - y + if r != -126 { + t.Errorf("1 - 127 = %d, want -126", r) + } + x = 126 + y = -128 + r = x - y + if r != -2 { + t.Errorf("126 - -128 = %d, want -2", r) + } + y = -127 + r = x - y + if r != -3 { + t.Errorf("126 - -127 = %d, want -3", r) + } + y = -1 + r = x - y + if r != 127 { + t.Errorf("126 - -1 = %d, want 127", r) + } + y = 0 + r = x - y + if r != 126 { + t.Errorf("126 - 0 = %d, want 126", r) + } + y = 1 + r = x - y + if r != 125 { + t.Errorf("126 - 1 = %d, want 125", r) + } + y = 126 + r = x - y + if r != 0 { + t.Errorf("126 - 126 = %d, want 0", r) + } + y = 127 + r = x - y + if r != -1 { + t.Errorf("126 - 127 = %d, want -1", r) + } + x = 127 + y = -128 + r = x - y + if r != -1 { + t.Errorf("127 - -128 = %d, want -1", r) + } + y = -127 + r = x - y + if r != -2 { + t.Errorf("127 - -127 = %d, want -2", r) + } + y = -1 + r = x - y + if r != -128 { + t.Errorf("127 - -1 = %d, want -128", r) + } + y = 0 + r = x - y + if r != 127 { + t.Errorf("127 - 0 = %d, want 127", r) + } + y = 1 + r = x - y + if r != 126 { + t.Errorf("127 - 1 = %d, want 126", r) + } + y = 126 + r = x - y + if r != 1 { + t.Errorf("127 - 126 = %d, want 1", r) + } + y = 127 + r = x - y + if r != 0 { + t.Errorf("127 - 127 = %d, want 0", r) + } +} +func TestConstFoldint8div(t *testing.T) { + var x, y, r int8 + x = -128 + y = -128 + r = x / y + if r != 1 { + t.Errorf("-128 / -128 = %d, want 1", r) + } + y = -127 + r = x / y + if r != 1 { + t.Errorf("-128 / -127 = %d, want 1", r) + } + y = -1 + r = x / y + if r != -128 { + t.Errorf("-128 / -1 = %d, want -128", r) + } + y = 1 + r = x / y + if r != -128 { + t.Errorf("-128 / 1 = %d, want -128", r) + } + y = 126 + r = x / y + if r != -1 { + t.Errorf("-128 / 126 = %d, want -1", r) + } + y = 127 + r = x / y + if r != -1 { + t.Errorf("-128 / 127 = %d, want -1", r) + } + x = -127 + y = -128 + r = x / y + if r != 0 { + t.Errorf("-127 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != 1 { + t.Errorf("-127 / -127 = %d, want 1", r) + } + y = -1 + r = x / y + if r != 127 { + t.Errorf("-127 / -1 = %d, want 127", r) + } + y = 1 + r = x / y + if r != -127 { + t.Errorf("-127 / 1 = %d, want -127", r) + } + y = 126 + r = x / y + if r != -1 { + t.Errorf("-127 / 126 = %d, want -1", r) + } + y = 127 + r = x / y + if r != -1 { + t.Errorf("-127 / 127 = %d, want -1", r) + } + x = -1 + y = -128 + r = x / y + if r != 0 { + t.Errorf("-1 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != 0 { + t.Errorf("-1 / -127 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 1 { + t.Errorf("-1 / -1 = %d, want 1", r) + } + y = 1 + r = x / y + if r != -1 { + t.Errorf("-1 / 1 = %d, want -1", r) + } + y = 126 + r = x / y + if r != 0 { + t.Errorf("-1 / 126 = %d, want 0", r) + } + y = 127 + r = x / y + if r != 0 { + t.Errorf("-1 / 127 = %d, want 0", r) + } + x = 0 + y = -128 + r = x / y + if r != 0 { + t.Errorf("0 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != 0 { + t.Errorf("0 / -127 = %d, want 0", r) + } + y = -1 + r = x / y + if r != 0 { + t.Errorf("0 / -1 = %d, want 0", r) + } + y = 1 + r = x / y + if r != 0 { + t.Errorf("0 / 1 = %d, want 0", r) + } + y = 126 + r = x / y + if r != 0 { + t.Errorf("0 / 126 = %d, want 0", r) + } + y = 127 + r = x / y + if r != 0 { + t.Errorf("0 / 127 = %d, want 0", r) + } + x = 1 + y = -128 + r = x / y + if r != 0 { + t.Errorf("1 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != 0 { + t.Errorf("1 / -127 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -1 { + t.Errorf("1 / -1 = %d, want -1", r) + } + y = 1 + r = x / y + if r != 1 { + t.Errorf("1 / 1 = %d, want 1", r) + } + y = 126 + r = x / y + if r != 0 { + t.Errorf("1 / 126 = %d, want 0", r) + } + y = 127 + r = x / y + if r != 0 { + t.Errorf("1 / 127 = %d, want 0", r) + } + x = 126 + y = -128 + r = x / y + if r != 0 { + t.Errorf("126 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != 0 { + t.Errorf("126 / -127 = %d, want 0", r) + } + y = -1 + r = x / y + if r != -126 { + t.Errorf("126 / -1 = %d, want -126", r) + } + y = 1 + r = x / y + if r != 126 { + t.Errorf("126 / 1 = %d, want 126", r) + } + y = 126 + r = x / y + if r != 1 { + t.Errorf("126 / 126 = %d, want 1", r) + } + y = 127 + r = x / y + if r != 0 { + t.Errorf("126 / 127 = %d, want 0", r) + } + x = 127 + y = -128 + r = x / y + if r != 0 { + t.Errorf("127 / -128 = %d, want 0", r) + } + y = -127 + r = x / y + if r != -1 { + t.Errorf("127 / -127 = %d, want -1", r) + } + y = -1 + r = x / y + if r != -127 { + t.Errorf("127 / -1 = %d, want -127", r) + } + y = 1 + r = x / y + if r != 127 { + t.Errorf("127 / 1 = %d, want 127", r) + } + y = 126 + r = x / y + if r != 1 { + t.Errorf("127 / 126 = %d, want 1", r) + } + y = 127 + r = x / y + if r != 1 { + t.Errorf("127 / 127 = %d, want 1", r) + } +} +func TestConstFoldint8mul(t *testing.T) { + var x, y, r int8 + x = -128 + y = -128 + r = x * y + if r != 0 { + t.Errorf("-128 * -128 = %d, want 0", r) + } + y = -127 + r = x * y + if r != -128 { + t.Errorf("-128 * -127 = %d, want -128", r) + } + y = -1 + r = x * y + if r != -128 { + t.Errorf("-128 * -1 = %d, want -128", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-128 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -128 { + t.Errorf("-128 * 1 = %d, want -128", r) + } + y = 126 + r = x * y + if r != 0 { + t.Errorf("-128 * 126 = %d, want 0", r) + } + y = 127 + r = x * y + if r != -128 { + t.Errorf("-128 * 127 = %d, want -128", r) + } + x = -127 + y = -128 + r = x * y + if r != -128 { + t.Errorf("-127 * -128 = %d, want -128", r) + } + y = -127 + r = x * y + if r != 1 { + t.Errorf("-127 * -127 = %d, want 1", r) + } + y = -1 + r = x * y + if r != 127 { + t.Errorf("-127 * -1 = %d, want 127", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-127 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -127 { + t.Errorf("-127 * 1 = %d, want -127", r) + } + y = 126 + r = x * y + if r != 126 { + t.Errorf("-127 * 126 = %d, want 126", r) + } + y = 127 + r = x * y + if r != -1 { + t.Errorf("-127 * 127 = %d, want -1", r) + } + x = -1 + y = -128 + r = x * y + if r != -128 { + t.Errorf("-1 * -128 = %d, want -128", r) + } + y = -127 + r = x * y + if r != 127 { + t.Errorf("-1 * -127 = %d, want 127", r) + } + y = -1 + r = x * y + if r != 1 { + t.Errorf("-1 * -1 = %d, want 1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("-1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != -1 { + t.Errorf("-1 * 1 = %d, want -1", r) + } + y = 126 + r = x * y + if r != -126 { + t.Errorf("-1 * 126 = %d, want -126", r) + } + y = 127 + r = x * y + if r != -127 { + t.Errorf("-1 * 127 = %d, want -127", r) + } + x = 0 + y = -128 + r = x * y + if r != 0 { + t.Errorf("0 * -128 = %d, want 0", r) + } + y = -127 + r = x * y + if r != 0 { + t.Errorf("0 * -127 = %d, want 0", r) + } + y = -1 + r = x * y + if r != 0 { + t.Errorf("0 * -1 = %d, want 0", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("0 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 0 { + t.Errorf("0 * 1 = %d, want 0", r) + } + y = 126 + r = x * y + if r != 0 { + t.Errorf("0 * 126 = %d, want 0", r) + } + y = 127 + r = x * y + if r != 0 { + t.Errorf("0 * 127 = %d, want 0", r) + } + x = 1 + y = -128 + r = x * y + if r != -128 { + t.Errorf("1 * -128 = %d, want -128", r) + } + y = -127 + r = x * y + if r != -127 { + t.Errorf("1 * -127 = %d, want -127", r) + } + y = -1 + r = x * y + if r != -1 { + t.Errorf("1 * -1 = %d, want -1", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("1 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 1 { + t.Errorf("1 * 1 = %d, want 1", r) + } + y = 126 + r = x * y + if r != 126 { + t.Errorf("1 * 126 = %d, want 126", r) + } + y = 127 + r = x * y + if r != 127 { + t.Errorf("1 * 127 = %d, want 127", r) + } + x = 126 + y = -128 + r = x * y + if r != 0 { + t.Errorf("126 * -128 = %d, want 0", r) + } + y = -127 + r = x * y + if r != 126 { + t.Errorf("126 * -127 = %d, want 126", r) + } + y = -1 + r = x * y + if r != -126 { + t.Errorf("126 * -1 = %d, want -126", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("126 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 126 { + t.Errorf("126 * 1 = %d, want 126", r) + } + y = 126 + r = x * y + if r != 4 { + t.Errorf("126 * 126 = %d, want 4", r) + } + y = 127 + r = x * y + if r != -126 { + t.Errorf("126 * 127 = %d, want -126", r) + } + x = 127 + y = -128 + r = x * y + if r != -128 { + t.Errorf("127 * -128 = %d, want -128", r) + } + y = -127 + r = x * y + if r != -1 { + t.Errorf("127 * -127 = %d, want -1", r) + } + y = -1 + r = x * y + if r != -127 { + t.Errorf("127 * -1 = %d, want -127", r) + } + y = 0 + r = x * y + if r != 0 { + t.Errorf("127 * 0 = %d, want 0", r) + } + y = 1 + r = x * y + if r != 127 { + t.Errorf("127 * 1 = %d, want 127", r) + } + y = 126 + r = x * y + if r != -126 { + t.Errorf("127 * 126 = %d, want -126", r) + } + y = 127 + r = x * y + if r != 1 { + t.Errorf("127 * 127 = %d, want 1", r) + } +} +func TestConstFoldint8mod(t *testing.T) { + var x, y, r int8 + x = -128 + y = -128 + r = x % y + if r != 0 { + t.Errorf("-128 % -128 = %d, want 0", r) + } + y = -127 + r = x % y + if r != -1 { + t.Errorf("-128 % -127 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-128 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-128 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != -2 { + t.Errorf("-128 % 126 = %d, want -2", r) + } + y = 127 + r = x % y + if r != -1 { + t.Errorf("-128 % 127 = %d, want -1", r) + } + x = -127 + y = -128 + r = x % y + if r != -127 { + t.Errorf("-127 % -128 = %d, want -127", r) + } + y = -127 + r = x % y + if r != 0 { + t.Errorf("-127 % -127 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-127 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-127 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != -1 { + t.Errorf("-127 % 126 = %d, want -1", r) + } + y = 127 + r = x % y + if r != 0 { + t.Errorf("-127 % 127 = %d, want 0", r) + } + x = -1 + y = -128 + r = x % y + if r != -1 { + t.Errorf("-1 % -128 = %d, want -1", r) + } + y = -127 + r = x % y + if r != -1 { + t.Errorf("-1 % -127 = %d, want -1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("-1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("-1 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != -1 { + t.Errorf("-1 % 126 = %d, want -1", r) + } + y = 127 + r = x % y + if r != -1 { + t.Errorf("-1 % 127 = %d, want -1", r) + } + x = 0 + y = -128 + r = x % y + if r != 0 { + t.Errorf("0 % -128 = %d, want 0", r) + } + y = -127 + r = x % y + if r != 0 { + t.Errorf("0 % -127 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("0 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("0 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != 0 { + t.Errorf("0 % 126 = %d, want 0", r) + } + y = 127 + r = x % y + if r != 0 { + t.Errorf("0 % 127 = %d, want 0", r) + } + x = 1 + y = -128 + r = x % y + if r != 1 { + t.Errorf("1 % -128 = %d, want 1", r) + } + y = -127 + r = x % y + if r != 1 { + t.Errorf("1 % -127 = %d, want 1", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("1 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("1 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != 1 { + t.Errorf("1 % 126 = %d, want 1", r) + } + y = 127 + r = x % y + if r != 1 { + t.Errorf("1 % 127 = %d, want 1", r) + } + x = 126 + y = -128 + r = x % y + if r != 126 { + t.Errorf("126 % -128 = %d, want 126", r) + } + y = -127 + r = x % y + if r != 126 { + t.Errorf("126 % -127 = %d, want 126", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("126 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("126 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != 0 { + t.Errorf("126 % 126 = %d, want 0", r) + } + y = 127 + r = x % y + if r != 126 { + t.Errorf("126 % 127 = %d, want 126", r) + } + x = 127 + y = -128 + r = x % y + if r != 127 { + t.Errorf("127 % -128 = %d, want 127", r) + } + y = -127 + r = x % y + if r != 0 { + t.Errorf("127 % -127 = %d, want 0", r) + } + y = -1 + r = x % y + if r != 0 { + t.Errorf("127 % -1 = %d, want 0", r) + } + y = 1 + r = x % y + if r != 0 { + t.Errorf("127 % 1 = %d, want 0", r) + } + y = 126 + r = x % y + if r != 1 { + t.Errorf("127 % 126 = %d, want 1", r) + } + y = 127 + r = x % y + if r != 0 { + t.Errorf("127 % 127 = %d, want 0", r) + } +} +func TestConstFolduint64uint64lsh(t *testing.T) { + var x, r uint64 + var y uint64 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x << y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x << y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("18446744073709551615 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("18446744073709551615 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint64uint64rsh(t *testing.T) { + var x, r uint64 + var y uint64 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x >> y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("18446744073709551615 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("18446744073709551615 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint64uint32lsh(t *testing.T) { + var x, r uint64 + var y uint32 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 4294967295 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x << y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x << y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("18446744073709551615 << 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint64uint32rsh(t *testing.T) { + var x, r uint64 + var y uint32 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 4294967295 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x >> y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("18446744073709551615 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint64uint16lsh(t *testing.T) { + var x, r uint64 + var y uint16 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 65535 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x << y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x << y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("18446744073709551615 << 65535 = %d, want 0", r) + } +} +func TestConstFolduint64uint16rsh(t *testing.T) { + var x, r uint64 + var y uint16 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 65535 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x >> y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("18446744073709551615 >> 65535 = %d, want 0", r) + } +} +func TestConstFolduint64uint8lsh(t *testing.T) { + var x, r uint64 + var y uint8 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 255 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x << y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x << y + if r != 18446744073709551614 { + t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("18446744073709551615 << 255 = %d, want 0", r) + } +} +func TestConstFolduint64uint8rsh(t *testing.T) { + var x, r uint64 + var y uint8 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 255 = %d, want 0", r) + } + x = 18446744073709551615 + y = 0 + r = x >> y + if r != 18446744073709551615 { + t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r) + } + y = 1 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("18446744073709551615 >> 255 = %d, want 0", r) + } +} +func TestConstFoldint64uint64lsh(t *testing.T) { + var x, r int64 + var y uint64 + x = -9223372036854775808 + y = 0 + r = x << y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 18446744073709551615 = %d, want 0", r) + } + x = -9223372036854775807 + y = 0 + r = x << y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-9223372036854775807 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775807 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775807 << 18446744073709551615 = %d, want 0", r) + } + x = -4294967296 + y = 0 + r = x << y + if r != -4294967296 { + t.Errorf("-4294967296 << 0 = %d, want -4294967296", r) + } + y = 1 + r = x << y + if r != -8589934592 { + t.Errorf("-4294967296 << 1 = %d, want -8589934592", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-4294967296 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-4294967296 << 18446744073709551615 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-1 << 18446744073709551615 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x << y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("9223372036854775806 << 1 = %d, want -4", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("9223372036854775806 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("9223372036854775806 << 18446744073709551615 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x << y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("9223372036854775807 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("9223372036854775807 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("9223372036854775807 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint64uint64rsh(t *testing.T) { + var x, r int64 + var y uint64 + x = -9223372036854775808 + y = 0 + r = x >> y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775808 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775808 >> 18446744073709551615 = %d, want -1", r) + } + x = -9223372036854775807 + y = 0 + r = x >> y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775807 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775807 >> 18446744073709551615 = %d, want -1", r) + } + x = -4294967296 + y = 0 + r = x >> y + if r != -4294967296 { + t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r) + } + y = 1 + r = x >> y + if r != -2147483648 { + t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-4294967296 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-4294967296 >> 18446744073709551615 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x >> y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775806 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775806 >> 18446744073709551615 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775807 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775807 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint64uint32lsh(t *testing.T) { + var x, r int64 + var y uint32 + x = -9223372036854775808 + y = 0 + r = x << y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 4294967295 = %d, want 0", r) + } + x = -9223372036854775807 + y = 0 + r = x << y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-9223372036854775807 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775807 << 4294967295 = %d, want 0", r) + } + x = -4294967296 + y = 0 + r = x << y + if r != -4294967296 { + t.Errorf("-4294967296 << 0 = %d, want -4294967296", r) + } + y = 1 + r = x << y + if r != -8589934592 { + t.Errorf("-4294967296 << 1 = %d, want -8589934592", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-4294967296 << 4294967295 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967295 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 4294967295 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x << y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("9223372036854775806 << 1 = %d, want -4", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("9223372036854775806 << 4294967295 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x << y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("9223372036854775807 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("9223372036854775807 << 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint64uint32rsh(t *testing.T) { + var x, r int64 + var y uint32 + x = -9223372036854775808 + y = 0 + r = x >> y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775808 >> 4294967295 = %d, want -1", r) + } + x = -9223372036854775807 + y = 0 + r = x >> y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775807 >> 4294967295 = %d, want -1", r) + } + x = -4294967296 + y = 0 + r = x >> y + if r != -4294967296 { + t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r) + } + y = 1 + r = x >> y + if r != -2147483648 { + t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-4294967296 >> 4294967295 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967295 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 4294967295 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x >> y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775806 >> 4294967295 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775807 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint64uint16lsh(t *testing.T) { + var x, r int64 + var y uint16 + x = -9223372036854775808 + y = 0 + r = x << y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 65535 = %d, want 0", r) + } + x = -9223372036854775807 + y = 0 + r = x << y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-9223372036854775807 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775807 << 65535 = %d, want 0", r) + } + x = -4294967296 + y = 0 + r = x << y + if r != -4294967296 { + t.Errorf("-4294967296 << 0 = %d, want -4294967296", r) + } + y = 1 + r = x << y + if r != -8589934592 { + t.Errorf("-4294967296 << 1 = %d, want -8589934592", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-4294967296 << 65535 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-1 << 65535 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 65535 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x << y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("9223372036854775806 << 1 = %d, want -4", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("9223372036854775806 << 65535 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x << y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("9223372036854775807 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("9223372036854775807 << 65535 = %d, want 0", r) + } +} +func TestConstFoldint64uint16rsh(t *testing.T) { + var x, r int64 + var y uint16 + x = -9223372036854775808 + y = 0 + r = x >> y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775808 >> 65535 = %d, want -1", r) + } + x = -9223372036854775807 + y = 0 + r = x >> y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775807 >> 65535 = %d, want -1", r) + } + x = -4294967296 + y = 0 + r = x >> y + if r != -4294967296 { + t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r) + } + y = 1 + r = x >> y + if r != -2147483648 { + t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-4294967296 >> 65535 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 65535 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 65535 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x >> y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775806 >> 65535 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775807 >> 65535 = %d, want 0", r) + } +} +func TestConstFoldint64uint8lsh(t *testing.T) { + var x, r int64 + var y uint8 + x = -9223372036854775808 + y = 0 + r = x << y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775808 << 255 = %d, want 0", r) + } + x = -9223372036854775807 + y = 0 + r = x << y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-9223372036854775807 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-9223372036854775807 << 255 = %d, want 0", r) + } + x = -4294967296 + y = 0 + r = x << y + if r != -4294967296 { + t.Errorf("-4294967296 << 0 = %d, want -4294967296", r) + } + y = 1 + r = x << y + if r != -8589934592 { + t.Errorf("-4294967296 << 1 = %d, want -8589934592", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-4294967296 << 255 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-1 << 255 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x << y + if r != 4294967296 { + t.Errorf("4294967296 << 0 = %d, want 4294967296", r) + } + y = 1 + r = x << y + if r != 8589934592 { + t.Errorf("4294967296 << 1 = %d, want 8589934592", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("4294967296 << 255 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x << y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("9223372036854775806 << 1 = %d, want -4", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("9223372036854775806 << 255 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x << y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("9223372036854775807 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("9223372036854775807 << 255 = %d, want 0", r) + } +} +func TestConstFoldint64uint8rsh(t *testing.T) { + var x, r int64 + var y uint8 + x = -9223372036854775808 + y = 0 + r = x >> y + if r != -9223372036854775808 { + t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775808 >> 255 = %d, want -1", r) + } + x = -9223372036854775807 + y = 0 + r = x >> y + if r != -9223372036854775807 { + t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r) + } + y = 1 + r = x >> y + if r != -4611686018427387904 { + t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-9223372036854775807 >> 255 = %d, want -1", r) + } + x = -4294967296 + y = 0 + r = x >> y + if r != -4294967296 { + t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r) + } + y = 1 + r = x >> y + if r != -2147483648 { + t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-4294967296 >> 255 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 255 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 4294967296 + y = 0 + r = x >> y + if r != 4294967296 { + t.Errorf("4294967296 >> 0 = %d, want 4294967296", r) + } + y = 1 + r = x >> y + if r != 2147483648 { + t.Errorf("4294967296 >> 1 = %d, want 2147483648", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("4294967296 >> 255 = %d, want 0", r) + } + x = 9223372036854775806 + y = 0 + r = x >> y + if r != 9223372036854775806 { + t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775806 >> 255 = %d, want 0", r) + } + x = 9223372036854775807 + y = 0 + r = x >> y + if r != 9223372036854775807 { + t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r) + } + y = 1 + r = x >> y + if r != 4611686018427387903 { + t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("9223372036854775807 >> 255 = %d, want 0", r) + } +} +func TestConstFolduint32uint64lsh(t *testing.T) { + var x, r uint32 + var y uint64 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x << y + if r != 4294967295 { + t.Errorf("4294967295 << 0 = %d, want 4294967295", r) + } + y = 1 + r = x << y + if r != 4294967294 { + t.Errorf("4294967295 << 1 = %d, want 4294967294", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("4294967295 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("4294967295 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint32uint64rsh(t *testing.T) { + var x, r uint32 + var y uint64 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x >> y + if r != 4294967295 { + t.Errorf("4294967295 >> 0 = %d, want 4294967295", r) + } + y = 1 + r = x >> y + if r != 2147483647 { + t.Errorf("4294967295 >> 1 = %d, want 2147483647", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("4294967295 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("4294967295 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint32uint32lsh(t *testing.T) { + var x, r uint32 + var y uint32 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x << y + if r != 4294967295 { + t.Errorf("4294967295 << 0 = %d, want 4294967295", r) + } + y = 1 + r = x << y + if r != 4294967294 { + t.Errorf("4294967295 << 1 = %d, want 4294967294", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("4294967295 << 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint32uint32rsh(t *testing.T) { + var x, r uint32 + var y uint32 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x >> y + if r != 4294967295 { + t.Errorf("4294967295 >> 0 = %d, want 4294967295", r) + } + y = 1 + r = x >> y + if r != 2147483647 { + t.Errorf("4294967295 >> 1 = %d, want 2147483647", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("4294967295 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint32uint16lsh(t *testing.T) { + var x, r uint32 + var y uint16 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x << y + if r != 4294967295 { + t.Errorf("4294967295 << 0 = %d, want 4294967295", r) + } + y = 1 + r = x << y + if r != 4294967294 { + t.Errorf("4294967295 << 1 = %d, want 4294967294", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("4294967295 << 65535 = %d, want 0", r) + } +} +func TestConstFolduint32uint16rsh(t *testing.T) { + var x, r uint32 + var y uint16 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x >> y + if r != 4294967295 { + t.Errorf("4294967295 >> 0 = %d, want 4294967295", r) + } + y = 1 + r = x >> y + if r != 2147483647 { + t.Errorf("4294967295 >> 1 = %d, want 2147483647", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("4294967295 >> 65535 = %d, want 0", r) + } +} +func TestConstFolduint32uint8lsh(t *testing.T) { + var x, r uint32 + var y uint8 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x << y + if r != 4294967295 { + t.Errorf("4294967295 << 0 = %d, want 4294967295", r) + } + y = 1 + r = x << y + if r != 4294967294 { + t.Errorf("4294967295 << 1 = %d, want 4294967294", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("4294967295 << 255 = %d, want 0", r) + } +} +func TestConstFolduint32uint8rsh(t *testing.T) { + var x, r uint32 + var y uint8 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 4294967295 + y = 0 + r = x >> y + if r != 4294967295 { + t.Errorf("4294967295 >> 0 = %d, want 4294967295", r) + } + y = 1 + r = x >> y + if r != 2147483647 { + t.Errorf("4294967295 >> 1 = %d, want 2147483647", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("4294967295 >> 255 = %d, want 0", r) + } +} +func TestConstFoldint32uint64lsh(t *testing.T) { + var x, r int32 + var y uint64 + x = -2147483648 + y = 0 + r = x << y + if r != -2147483648 { + t.Errorf("-2147483648 << 0 = %d, want -2147483648", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 18446744073709551615 = %d, want 0", r) + } + x = -2147483647 + y = 0 + r = x << y + if r != -2147483647 { + t.Errorf("-2147483647 << 0 = %d, want -2147483647", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-2147483647 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-2147483647 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-2147483647 << 18446744073709551615 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-1 << 18446744073709551615 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x << y + if r != 2147483647 { + t.Errorf("2147483647 << 0 = %d, want 2147483647", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("2147483647 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("2147483647 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("2147483647 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint32uint64rsh(t *testing.T) { + var x, r int32 + var y uint64 + x = -2147483648 + y = 0 + r = x >> y + if r != -2147483648 { + t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-2147483648 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-2147483648 >> 18446744073709551615 = %d, want -1", r) + } + x = -2147483647 + y = 0 + r = x >> y + if r != -2147483647 { + t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-2147483647 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-2147483647 >> 18446744073709551615 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x >> y + if r != 2147483647 { + t.Errorf("2147483647 >> 0 = %d, want 2147483647", r) + } + y = 1 + r = x >> y + if r != 1073741823 { + t.Errorf("2147483647 >> 1 = %d, want 1073741823", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("2147483647 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("2147483647 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint32uint32lsh(t *testing.T) { + var x, r int32 + var y uint32 + x = -2147483648 + y = 0 + r = x << y + if r != -2147483648 { + t.Errorf("-2147483648 << 0 = %d, want -2147483648", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 4294967295 = %d, want 0", r) + } + x = -2147483647 + y = 0 + r = x << y + if r != -2147483647 { + t.Errorf("-2147483647 << 0 = %d, want -2147483647", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-2147483647 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-2147483647 << 4294967295 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967295 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x << y + if r != 2147483647 { + t.Errorf("2147483647 << 0 = %d, want 2147483647", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("2147483647 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("2147483647 << 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint32uint32rsh(t *testing.T) { + var x, r int32 + var y uint32 + x = -2147483648 + y = 0 + r = x >> y + if r != -2147483648 { + t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-2147483648 >> 4294967295 = %d, want -1", r) + } + x = -2147483647 + y = 0 + r = x >> y + if r != -2147483647 { + t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-2147483647 >> 4294967295 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967295 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x >> y + if r != 2147483647 { + t.Errorf("2147483647 >> 0 = %d, want 2147483647", r) + } + y = 1 + r = x >> y + if r != 1073741823 { + t.Errorf("2147483647 >> 1 = %d, want 1073741823", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("2147483647 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint32uint16lsh(t *testing.T) { + var x, r int32 + var y uint16 + x = -2147483648 + y = 0 + r = x << y + if r != -2147483648 { + t.Errorf("-2147483648 << 0 = %d, want -2147483648", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 65535 = %d, want 0", r) + } + x = -2147483647 + y = 0 + r = x << y + if r != -2147483647 { + t.Errorf("-2147483647 << 0 = %d, want -2147483647", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-2147483647 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-2147483647 << 65535 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-1 << 65535 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x << y + if r != 2147483647 { + t.Errorf("2147483647 << 0 = %d, want 2147483647", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("2147483647 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("2147483647 << 65535 = %d, want 0", r) + } +} +func TestConstFoldint32uint16rsh(t *testing.T) { + var x, r int32 + var y uint16 + x = -2147483648 + y = 0 + r = x >> y + if r != -2147483648 { + t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-2147483648 >> 65535 = %d, want -1", r) + } + x = -2147483647 + y = 0 + r = x >> y + if r != -2147483647 { + t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-2147483647 >> 65535 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 65535 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x >> y + if r != 2147483647 { + t.Errorf("2147483647 >> 0 = %d, want 2147483647", r) + } + y = 1 + r = x >> y + if r != 1073741823 { + t.Errorf("2147483647 >> 1 = %d, want 1073741823", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("2147483647 >> 65535 = %d, want 0", r) + } +} +func TestConstFoldint32uint8lsh(t *testing.T) { + var x, r int32 + var y uint8 + x = -2147483648 + y = 0 + r = x << y + if r != -2147483648 { + t.Errorf("-2147483648 << 0 = %d, want -2147483648", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-2147483648 << 255 = %d, want 0", r) + } + x = -2147483647 + y = 0 + r = x << y + if r != -2147483647 { + t.Errorf("-2147483647 << 0 = %d, want -2147483647", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-2147483647 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-2147483647 << 255 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-1 << 255 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x << y + if r != 2147483647 { + t.Errorf("2147483647 << 0 = %d, want 2147483647", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("2147483647 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("2147483647 << 255 = %d, want 0", r) + } +} +func TestConstFoldint32uint8rsh(t *testing.T) { + var x, r int32 + var y uint8 + x = -2147483648 + y = 0 + r = x >> y + if r != -2147483648 { + t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-2147483648 >> 255 = %d, want -1", r) + } + x = -2147483647 + y = 0 + r = x >> y + if r != -2147483647 { + t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r) + } + y = 1 + r = x >> y + if r != -1073741824 { + t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-2147483647 >> 255 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 255 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 2147483647 + y = 0 + r = x >> y + if r != 2147483647 { + t.Errorf("2147483647 >> 0 = %d, want 2147483647", r) + } + y = 1 + r = x >> y + if r != 1073741823 { + t.Errorf("2147483647 >> 1 = %d, want 1073741823", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("2147483647 >> 255 = %d, want 0", r) + } +} +func TestConstFolduint16uint64lsh(t *testing.T) { + var x, r uint16 + var y uint64 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x << y + if r != 65535 { + t.Errorf("65535 << 0 = %d, want 65535", r) + } + y = 1 + r = x << y + if r != 65534 { + t.Errorf("65535 << 1 = %d, want 65534", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("65535 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("65535 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint16uint64rsh(t *testing.T) { + var x, r uint16 + var y uint64 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x >> y + if r != 65535 { + t.Errorf("65535 >> 0 = %d, want 65535", r) + } + y = 1 + r = x >> y + if r != 32767 { + t.Errorf("65535 >> 1 = %d, want 32767", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("65535 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("65535 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint16uint32lsh(t *testing.T) { + var x, r uint16 + var y uint32 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x << y + if r != 65535 { + t.Errorf("65535 << 0 = %d, want 65535", r) + } + y = 1 + r = x << y + if r != 65534 { + t.Errorf("65535 << 1 = %d, want 65534", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("65535 << 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint16uint32rsh(t *testing.T) { + var x, r uint16 + var y uint32 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x >> y + if r != 65535 { + t.Errorf("65535 >> 0 = %d, want 65535", r) + } + y = 1 + r = x >> y + if r != 32767 { + t.Errorf("65535 >> 1 = %d, want 32767", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("65535 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint16uint16lsh(t *testing.T) { + var x, r uint16 + var y uint16 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x << y + if r != 65535 { + t.Errorf("65535 << 0 = %d, want 65535", r) + } + y = 1 + r = x << y + if r != 65534 { + t.Errorf("65535 << 1 = %d, want 65534", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("65535 << 65535 = %d, want 0", r) + } +} +func TestConstFolduint16uint16rsh(t *testing.T) { + var x, r uint16 + var y uint16 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x >> y + if r != 65535 { + t.Errorf("65535 >> 0 = %d, want 65535", r) + } + y = 1 + r = x >> y + if r != 32767 { + t.Errorf("65535 >> 1 = %d, want 32767", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("65535 >> 65535 = %d, want 0", r) + } +} +func TestConstFolduint16uint8lsh(t *testing.T) { + var x, r uint16 + var y uint8 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x << y + if r != 65535 { + t.Errorf("65535 << 0 = %d, want 65535", r) + } + y = 1 + r = x << y + if r != 65534 { + t.Errorf("65535 << 1 = %d, want 65534", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("65535 << 255 = %d, want 0", r) + } +} +func TestConstFolduint16uint8rsh(t *testing.T) { + var x, r uint16 + var y uint8 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 65535 + y = 0 + r = x >> y + if r != 65535 { + t.Errorf("65535 >> 0 = %d, want 65535", r) + } + y = 1 + r = x >> y + if r != 32767 { + t.Errorf("65535 >> 1 = %d, want 32767", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("65535 >> 255 = %d, want 0", r) + } +} +func TestConstFoldint16uint64lsh(t *testing.T) { + var x, r int16 + var y uint64 + x = -32768 + y = 0 + r = x << y + if r != -32768 { + t.Errorf("-32768 << 0 = %d, want -32768", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-32768 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-32768 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-32768 << 18446744073709551615 = %d, want 0", r) + } + x = -32767 + y = 0 + r = x << y + if r != -32767 { + t.Errorf("-32767 << 0 = %d, want -32767", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-32767 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-32767 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-32767 << 18446744073709551615 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-1 << 18446744073709551615 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x << y + if r != 32766 { + t.Errorf("32766 << 0 = %d, want 32766", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("32766 << 1 = %d, want -4", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("32766 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("32766 << 18446744073709551615 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x << y + if r != 32767 { + t.Errorf("32767 << 0 = %d, want 32767", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("32767 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("32767 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("32767 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint16uint64rsh(t *testing.T) { + var x, r int16 + var y uint64 + x = -32768 + y = 0 + r = x >> y + if r != -32768 { + t.Errorf("-32768 >> 0 = %d, want -32768", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32768 >> 1 = %d, want -16384", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-32768 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-32768 >> 18446744073709551615 = %d, want -1", r) + } + x = -32767 + y = 0 + r = x >> y + if r != -32767 { + t.Errorf("-32767 >> 0 = %d, want -32767", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32767 >> 1 = %d, want -16384", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-32767 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-32767 >> 18446744073709551615 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x >> y + if r != 32766 { + t.Errorf("32766 >> 0 = %d, want 32766", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32766 >> 1 = %d, want 16383", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("32766 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("32766 >> 18446744073709551615 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x >> y + if r != 32767 { + t.Errorf("32767 >> 0 = %d, want 32767", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32767 >> 1 = %d, want 16383", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("32767 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("32767 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint16uint32lsh(t *testing.T) { + var x, r int16 + var y uint32 + x = -32768 + y = 0 + r = x << y + if r != -32768 { + t.Errorf("-32768 << 0 = %d, want -32768", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-32768 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-32768 << 4294967295 = %d, want 0", r) + } + x = -32767 + y = 0 + r = x << y + if r != -32767 { + t.Errorf("-32767 << 0 = %d, want -32767", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-32767 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-32767 << 4294967295 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967295 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x << y + if r != 32766 { + t.Errorf("32766 << 0 = %d, want 32766", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("32766 << 1 = %d, want -4", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("32766 << 4294967295 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x << y + if r != 32767 { + t.Errorf("32767 << 0 = %d, want 32767", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("32767 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("32767 << 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint16uint32rsh(t *testing.T) { + var x, r int16 + var y uint32 + x = -32768 + y = 0 + r = x >> y + if r != -32768 { + t.Errorf("-32768 >> 0 = %d, want -32768", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32768 >> 1 = %d, want -16384", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-32768 >> 4294967295 = %d, want -1", r) + } + x = -32767 + y = 0 + r = x >> y + if r != -32767 { + t.Errorf("-32767 >> 0 = %d, want -32767", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32767 >> 1 = %d, want -16384", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-32767 >> 4294967295 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967295 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x >> y + if r != 32766 { + t.Errorf("32766 >> 0 = %d, want 32766", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32766 >> 1 = %d, want 16383", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("32766 >> 4294967295 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x >> y + if r != 32767 { + t.Errorf("32767 >> 0 = %d, want 32767", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32767 >> 1 = %d, want 16383", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("32767 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint16uint16lsh(t *testing.T) { + var x, r int16 + var y uint16 + x = -32768 + y = 0 + r = x << y + if r != -32768 { + t.Errorf("-32768 << 0 = %d, want -32768", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-32768 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-32768 << 65535 = %d, want 0", r) + } + x = -32767 + y = 0 + r = x << y + if r != -32767 { + t.Errorf("-32767 << 0 = %d, want -32767", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-32767 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-32767 << 65535 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-1 << 65535 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x << y + if r != 32766 { + t.Errorf("32766 << 0 = %d, want 32766", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("32766 << 1 = %d, want -4", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("32766 << 65535 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x << y + if r != 32767 { + t.Errorf("32767 << 0 = %d, want 32767", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("32767 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("32767 << 65535 = %d, want 0", r) + } +} +func TestConstFoldint16uint16rsh(t *testing.T) { + var x, r int16 + var y uint16 + x = -32768 + y = 0 + r = x >> y + if r != -32768 { + t.Errorf("-32768 >> 0 = %d, want -32768", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32768 >> 1 = %d, want -16384", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-32768 >> 65535 = %d, want -1", r) + } + x = -32767 + y = 0 + r = x >> y + if r != -32767 { + t.Errorf("-32767 >> 0 = %d, want -32767", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32767 >> 1 = %d, want -16384", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-32767 >> 65535 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 65535 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x >> y + if r != 32766 { + t.Errorf("32766 >> 0 = %d, want 32766", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32766 >> 1 = %d, want 16383", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("32766 >> 65535 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x >> y + if r != 32767 { + t.Errorf("32767 >> 0 = %d, want 32767", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32767 >> 1 = %d, want 16383", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("32767 >> 65535 = %d, want 0", r) + } +} +func TestConstFoldint16uint8lsh(t *testing.T) { + var x, r int16 + var y uint8 + x = -32768 + y = 0 + r = x << y + if r != -32768 { + t.Errorf("-32768 << 0 = %d, want -32768", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-32768 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-32768 << 255 = %d, want 0", r) + } + x = -32767 + y = 0 + r = x << y + if r != -32767 { + t.Errorf("-32767 << 0 = %d, want -32767", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-32767 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-32767 << 255 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-1 << 255 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x << y + if r != 32766 { + t.Errorf("32766 << 0 = %d, want 32766", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("32766 << 1 = %d, want -4", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("32766 << 255 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x << y + if r != 32767 { + t.Errorf("32767 << 0 = %d, want 32767", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("32767 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("32767 << 255 = %d, want 0", r) + } +} +func TestConstFoldint16uint8rsh(t *testing.T) { + var x, r int16 + var y uint8 + x = -32768 + y = 0 + r = x >> y + if r != -32768 { + t.Errorf("-32768 >> 0 = %d, want -32768", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32768 >> 1 = %d, want -16384", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-32768 >> 255 = %d, want -1", r) + } + x = -32767 + y = 0 + r = x >> y + if r != -32767 { + t.Errorf("-32767 >> 0 = %d, want -32767", r) + } + y = 1 + r = x >> y + if r != -16384 { + t.Errorf("-32767 >> 1 = %d, want -16384", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-32767 >> 255 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 255 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 32766 + y = 0 + r = x >> y + if r != 32766 { + t.Errorf("32766 >> 0 = %d, want 32766", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32766 >> 1 = %d, want 16383", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("32766 >> 255 = %d, want 0", r) + } + x = 32767 + y = 0 + r = x >> y + if r != 32767 { + t.Errorf("32767 >> 0 = %d, want 32767", r) + } + y = 1 + r = x >> y + if r != 16383 { + t.Errorf("32767 >> 1 = %d, want 16383", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("32767 >> 255 = %d, want 0", r) + } +} +func TestConstFolduint8uint64lsh(t *testing.T) { + var x, r uint8 + var y uint64 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 255 + y = 0 + r = x << y + if r != 255 { + t.Errorf("255 << 0 = %d, want 255", r) + } + y = 1 + r = x << y + if r != 254 { + t.Errorf("255 << 1 = %d, want 254", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("255 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("255 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint8uint64rsh(t *testing.T) { + var x, r uint8 + var y uint64 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 255 + y = 0 + r = x >> y + if r != 255 { + t.Errorf("255 >> 0 = %d, want 255", r) + } + y = 1 + r = x >> y + if r != 127 { + t.Errorf("255 >> 1 = %d, want 127", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("255 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("255 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFolduint8uint32lsh(t *testing.T) { + var x, r uint8 + var y uint32 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 255 + y = 0 + r = x << y + if r != 255 { + t.Errorf("255 << 0 = %d, want 255", r) + } + y = 1 + r = x << y + if r != 254 { + t.Errorf("255 << 1 = %d, want 254", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("255 << 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint8uint32rsh(t *testing.T) { + var x, r uint8 + var y uint32 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 255 + y = 0 + r = x >> y + if r != 255 { + t.Errorf("255 >> 0 = %d, want 255", r) + } + y = 1 + r = x >> y + if r != 127 { + t.Errorf("255 >> 1 = %d, want 127", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("255 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFolduint8uint16lsh(t *testing.T) { + var x, r uint8 + var y uint16 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 255 + y = 0 + r = x << y + if r != 255 { + t.Errorf("255 << 0 = %d, want 255", r) + } + y = 1 + r = x << y + if r != 254 { + t.Errorf("255 << 1 = %d, want 254", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("255 << 65535 = %d, want 0", r) + } +} +func TestConstFolduint8uint16rsh(t *testing.T) { + var x, r uint8 + var y uint16 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 255 + y = 0 + r = x >> y + if r != 255 { + t.Errorf("255 >> 0 = %d, want 255", r) + } + y = 1 + r = x >> y + if r != 127 { + t.Errorf("255 >> 1 = %d, want 127", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("255 >> 65535 = %d, want 0", r) + } +} +func TestConstFolduint8uint8lsh(t *testing.T) { + var x, r uint8 + var y uint8 + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 255 + y = 0 + r = x << y + if r != 255 { + t.Errorf("255 << 0 = %d, want 255", r) + } + y = 1 + r = x << y + if r != 254 { + t.Errorf("255 << 1 = %d, want 254", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("255 << 255 = %d, want 0", r) + } +} +func TestConstFolduint8uint8rsh(t *testing.T) { + var x, r uint8 + var y uint8 + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 255 + y = 0 + r = x >> y + if r != 255 { + t.Errorf("255 >> 0 = %d, want 255", r) + } + y = 1 + r = x >> y + if r != 127 { + t.Errorf("255 >> 1 = %d, want 127", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("255 >> 255 = %d, want 0", r) + } +} +func TestConstFoldint8uint64lsh(t *testing.T) { + var x, r int8 + var y uint64 + x = -128 + y = 0 + r = x << y + if r != -128 { + t.Errorf("-128 << 0 = %d, want -128", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-128 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-128 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-128 << 18446744073709551615 = %d, want 0", r) + } + x = -127 + y = 0 + r = x << y + if r != -127 { + t.Errorf("-127 << 0 = %d, want -127", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-127 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-127 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-127 << 18446744073709551615 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("-1 << 18446744073709551615 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("0 << 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("1 << 18446744073709551615 = %d, want 0", r) + } + x = 126 + y = 0 + r = x << y + if r != 126 { + t.Errorf("126 << 0 = %d, want 126", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("126 << 1 = %d, want -4", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("126 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("126 << 18446744073709551615 = %d, want 0", r) + } + x = 127 + y = 0 + r = x << y + if r != 127 { + t.Errorf("127 << 0 = %d, want 127", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("127 << 1 = %d, want -2", r) + } + y = 4294967296 + r = x << y + if r != 0 { + t.Errorf("127 << 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x << y + if r != 0 { + t.Errorf("127 << 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint8uint64rsh(t *testing.T) { + var x, r int8 + var y uint64 + x = -128 + y = 0 + r = x >> y + if r != -128 { + t.Errorf("-128 >> 0 = %d, want -128", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-128 >> 1 = %d, want -64", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-128 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-128 >> 18446744073709551615 = %d, want -1", r) + } + x = -127 + y = 0 + r = x >> y + if r != -127 { + t.Errorf("-127 >> 0 = %d, want -127", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-127 >> 1 = %d, want -64", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-127 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-127 >> 18446744073709551615 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967296 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967296 = %d, want -1", r) + } + y = 18446744073709551615 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("0 >> 18446744073709551615 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("1 >> 18446744073709551615 = %d, want 0", r) + } + x = 126 + y = 0 + r = x >> y + if r != 126 { + t.Errorf("126 >> 0 = %d, want 126", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("126 >> 1 = %d, want 63", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("126 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("126 >> 18446744073709551615 = %d, want 0", r) + } + x = 127 + y = 0 + r = x >> y + if r != 127 { + t.Errorf("127 >> 0 = %d, want 127", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("127 >> 1 = %d, want 63", r) + } + y = 4294967296 + r = x >> y + if r != 0 { + t.Errorf("127 >> 4294967296 = %d, want 0", r) + } + y = 18446744073709551615 + r = x >> y + if r != 0 { + t.Errorf("127 >> 18446744073709551615 = %d, want 0", r) + } +} +func TestConstFoldint8uint32lsh(t *testing.T) { + var x, r int8 + var y uint32 + x = -128 + y = 0 + r = x << y + if r != -128 { + t.Errorf("-128 << 0 = %d, want -128", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-128 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-128 << 4294967295 = %d, want 0", r) + } + x = -127 + y = 0 + r = x << y + if r != -127 { + t.Errorf("-127 << 0 = %d, want -127", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-127 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-127 << 4294967295 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("-1 << 4294967295 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("0 << 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("1 << 4294967295 = %d, want 0", r) + } + x = 126 + y = 0 + r = x << y + if r != 126 { + t.Errorf("126 << 0 = %d, want 126", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("126 << 1 = %d, want -4", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("126 << 4294967295 = %d, want 0", r) + } + x = 127 + y = 0 + r = x << y + if r != 127 { + t.Errorf("127 << 0 = %d, want 127", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("127 << 1 = %d, want -2", r) + } + y = 4294967295 + r = x << y + if r != 0 { + t.Errorf("127 << 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint8uint32rsh(t *testing.T) { + var x, r int8 + var y uint32 + x = -128 + y = 0 + r = x >> y + if r != -128 { + t.Errorf("-128 >> 0 = %d, want -128", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-128 >> 1 = %d, want -64", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-128 >> 4294967295 = %d, want -1", r) + } + x = -127 + y = 0 + r = x >> y + if r != -127 { + t.Errorf("-127 >> 0 = %d, want -127", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-127 >> 1 = %d, want -64", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-127 >> 4294967295 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 4294967295 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 4294967295 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("0 >> 4294967295 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("1 >> 4294967295 = %d, want 0", r) + } + x = 126 + y = 0 + r = x >> y + if r != 126 { + t.Errorf("126 >> 0 = %d, want 126", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("126 >> 1 = %d, want 63", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("126 >> 4294967295 = %d, want 0", r) + } + x = 127 + y = 0 + r = x >> y + if r != 127 { + t.Errorf("127 >> 0 = %d, want 127", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("127 >> 1 = %d, want 63", r) + } + y = 4294967295 + r = x >> y + if r != 0 { + t.Errorf("127 >> 4294967295 = %d, want 0", r) + } +} +func TestConstFoldint8uint16lsh(t *testing.T) { + var x, r int8 + var y uint16 + x = -128 + y = 0 + r = x << y + if r != -128 { + t.Errorf("-128 << 0 = %d, want -128", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-128 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-128 << 65535 = %d, want 0", r) + } + x = -127 + y = 0 + r = x << y + if r != -127 { + t.Errorf("-127 << 0 = %d, want -127", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-127 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-127 << 65535 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("-1 << 65535 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("0 << 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("1 << 65535 = %d, want 0", r) + } + x = 126 + y = 0 + r = x << y + if r != 126 { + t.Errorf("126 << 0 = %d, want 126", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("126 << 1 = %d, want -4", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("126 << 65535 = %d, want 0", r) + } + x = 127 + y = 0 + r = x << y + if r != 127 { + t.Errorf("127 << 0 = %d, want 127", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("127 << 1 = %d, want -2", r) + } + y = 65535 + r = x << y + if r != 0 { + t.Errorf("127 << 65535 = %d, want 0", r) + } +} +func TestConstFoldint8uint16rsh(t *testing.T) { + var x, r int8 + var y uint16 + x = -128 + y = 0 + r = x >> y + if r != -128 { + t.Errorf("-128 >> 0 = %d, want -128", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-128 >> 1 = %d, want -64", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-128 >> 65535 = %d, want -1", r) + } + x = -127 + y = 0 + r = x >> y + if r != -127 { + t.Errorf("-127 >> 0 = %d, want -127", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-127 >> 1 = %d, want -64", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-127 >> 65535 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 65535 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 65535 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("0 >> 65535 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("1 >> 65535 = %d, want 0", r) + } + x = 126 + y = 0 + r = x >> y + if r != 126 { + t.Errorf("126 >> 0 = %d, want 126", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("126 >> 1 = %d, want 63", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("126 >> 65535 = %d, want 0", r) + } + x = 127 + y = 0 + r = x >> y + if r != 127 { + t.Errorf("127 >> 0 = %d, want 127", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("127 >> 1 = %d, want 63", r) + } + y = 65535 + r = x >> y + if r != 0 { + t.Errorf("127 >> 65535 = %d, want 0", r) + } +} +func TestConstFoldint8uint8lsh(t *testing.T) { + var x, r int8 + var y uint8 + x = -128 + y = 0 + r = x << y + if r != -128 { + t.Errorf("-128 << 0 = %d, want -128", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("-128 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-128 << 255 = %d, want 0", r) + } + x = -127 + y = 0 + r = x << y + if r != -127 { + t.Errorf("-127 << 0 = %d, want -127", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("-127 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-127 << 255 = %d, want 0", r) + } + x = -1 + y = 0 + r = x << y + if r != -1 { + t.Errorf("-1 << 0 = %d, want -1", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("-1 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("-1 << 255 = %d, want 0", r) + } + x = 0 + y = 0 + r = x << y + if r != 0 { + t.Errorf("0 << 0 = %d, want 0", r) + } + y = 1 + r = x << y + if r != 0 { + t.Errorf("0 << 1 = %d, want 0", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("0 << 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x << y + if r != 1 { + t.Errorf("1 << 0 = %d, want 1", r) + } + y = 1 + r = x << y + if r != 2 { + t.Errorf("1 << 1 = %d, want 2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("1 << 255 = %d, want 0", r) + } + x = 126 + y = 0 + r = x << y + if r != 126 { + t.Errorf("126 << 0 = %d, want 126", r) + } + y = 1 + r = x << y + if r != -4 { + t.Errorf("126 << 1 = %d, want -4", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("126 << 255 = %d, want 0", r) + } + x = 127 + y = 0 + r = x << y + if r != 127 { + t.Errorf("127 << 0 = %d, want 127", r) + } + y = 1 + r = x << y + if r != -2 { + t.Errorf("127 << 1 = %d, want -2", r) + } + y = 255 + r = x << y + if r != 0 { + t.Errorf("127 << 255 = %d, want 0", r) + } +} +func TestConstFoldint8uint8rsh(t *testing.T) { + var x, r int8 + var y uint8 + x = -128 + y = 0 + r = x >> y + if r != -128 { + t.Errorf("-128 >> 0 = %d, want -128", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-128 >> 1 = %d, want -64", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-128 >> 255 = %d, want -1", r) + } + x = -127 + y = 0 + r = x >> y + if r != -127 { + t.Errorf("-127 >> 0 = %d, want -127", r) + } + y = 1 + r = x >> y + if r != -64 { + t.Errorf("-127 >> 1 = %d, want -64", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-127 >> 255 = %d, want -1", r) + } + x = -1 + y = 0 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 0 = %d, want -1", r) + } + y = 1 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 1 = %d, want -1", r) + } + y = 255 + r = x >> y + if r != -1 { + t.Errorf("-1 >> 255 = %d, want -1", r) + } + x = 0 + y = 0 + r = x >> y + if r != 0 { + t.Errorf("0 >> 0 = %d, want 0", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("0 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("0 >> 255 = %d, want 0", r) + } + x = 1 + y = 0 + r = x >> y + if r != 1 { + t.Errorf("1 >> 0 = %d, want 1", r) + } + y = 1 + r = x >> y + if r != 0 { + t.Errorf("1 >> 1 = %d, want 0", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("1 >> 255 = %d, want 0", r) + } + x = 126 + y = 0 + r = x >> y + if r != 126 { + t.Errorf("126 >> 0 = %d, want 126", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("126 >> 1 = %d, want 63", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("126 >> 255 = %d, want 0", r) + } + x = 127 + y = 0 + r = x >> y + if r != 127 { + t.Errorf("127 >> 0 = %d, want 127", r) + } + y = 1 + r = x >> y + if r != 63 { + t.Errorf("127 >> 1 = %d, want 63", r) + } + y = 255 + r = x >> y + if r != 0 { + t.Errorf("127 >> 255 = %d, want 0", r) + } +} diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go new file mode 100644 index 00000000000000..eea6165938e81f --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go @@ -0,0 +1,224 @@ +// 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 program generates a test to verify that the standard arithmetic +// operators properly handle constant folding. The test file should be +// generated with a known working version of go. +// launch with `go run constFoldGen.go` a file called constFold_test.go +// will be written into the grandparent directory containing the tests. + +package main + +import ( + "bytes" + "fmt" + "go/format" + "io/ioutil" + "log" +) + +type op struct { + name, symbol string +} +type szD struct { + name string + sn string + u []uint64 + i []int64 +} + +var szs []szD = []szD{ + szD{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}}, + szD{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF, + -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}}, + + szD{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}}, + szD{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0, + 1, 0x7FFFFFFF}}, + + szD{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}}, + szD{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}}, + + szD{name: "uint8", sn: "8", u: []uint64{0, 1, 255}}, + szD{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}}, +} + +var ops = []op{ + op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mul", "*"}, + op{"lsh", "<<"}, op{"rsh", ">>"}, op{"mod", "%"}, +} + +// compute the result of i op j, cast as type t. +func ansU(i, j uint64, t, op string) string { + var ans uint64 + switch op { + case "+": + ans = i + j + case "-": + ans = i - j + case "*": + ans = i * j + case "/": + if j != 0 { + ans = i / j + } + case "%": + if j != 0 { + ans = i % j + } + case "<<": + ans = i << j + case ">>": + ans = i >> j + } + switch t { + case "uint32": + ans = uint64(uint32(ans)) + case "uint16": + ans = uint64(uint16(ans)) + case "uint8": + ans = uint64(uint8(ans)) + } + return fmt.Sprintf("%d", ans) +} + +// compute the result of i op j, cast as type t. +func ansS(i, j int64, t, op string) string { + var ans int64 + switch op { + case "+": + ans = i + j + case "-": + ans = i - j + case "*": + ans = i * j + case "/": + if j != 0 { + ans = i / j + } + case "%": + if j != 0 { + ans = i % j + } + case "<<": + ans = i << uint64(j) + case ">>": + ans = i >> uint64(j) + } + switch t { + case "int32": + ans = int64(int32(ans)) + case "int16": + ans = int64(int16(ans)) + case "int8": + ans = int64(int8(ans)) + } + return fmt.Sprintf("%d", ans) +} + +func main() { + + w := new(bytes.Buffer) + + fmt.Fprintf(w, "package gc\n") + fmt.Fprintf(w, "import \"testing\"\n") + + for _, s := range szs { + for _, o := range ops { + if o.symbol == "<<" || o.symbol == ">>" { + // shifts handled separately below, as they can have + // different types on the LHS and RHS. + continue + } + fmt.Fprintf(w, "func TestConstFold%s%s(t *testing.T) {\n", s.name, o.name) + fmt.Fprintf(w, "\tvar x, y, r %s\n", s.name) + // unsigned test cases + for _, c := range s.u { + fmt.Fprintf(w, "\tx = %d\n", c) + for _, d := range s.u { + if d == 0 && (o.symbol == "/" || o.symbol == "%") { + continue + } + fmt.Fprintf(w, "\ty = %d\n", d) + fmt.Fprintf(w, "\tr = x %s y\n", o.symbol) + want := ansU(c, d, s.name, o.symbol) + fmt.Fprintf(w, "\tif r != %s {\n", want) + fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want) + fmt.Fprintf(w, "\t}\n") + } + } + // signed test cases + for _, c := range s.i { + fmt.Fprintf(w, "\tx = %d\n", c) + for _, d := range s.i { + if d == 0 && (o.symbol == "/" || o.symbol == "%") { + continue + } + fmt.Fprintf(w, "\ty = %d\n", d) + fmt.Fprintf(w, "\tr = x %s y\n", o.symbol) + want := ansS(c, d, s.name, o.symbol) + fmt.Fprintf(w, "\tif r != %s {\n", want) + fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want) + fmt.Fprintf(w, "\t}\n") + } + } + fmt.Fprintf(w, "}\n") + } + } + + // Special signed/unsigned cases for shifts + for _, ls := range szs { + for _, rs := range szs { + if rs.name[0] != 'u' { + continue + } + for _, o := range ops { + if o.symbol != "<<" && o.symbol != ">>" { + continue + } + fmt.Fprintf(w, "func TestConstFold%s%s%s(t *testing.T) {\n", ls.name, rs.name, o.name) + fmt.Fprintf(w, "\tvar x, r %s\n", ls.name) + fmt.Fprintf(w, "\tvar y %s\n", rs.name) + // unsigned LHS + for _, c := range ls.u { + fmt.Fprintf(w, "\tx = %d\n", c) + for _, d := range rs.u { + fmt.Fprintf(w, "\ty = %d\n", d) + fmt.Fprintf(w, "\tr = x %s y\n", o.symbol) + want := ansU(c, d, ls.name, o.symbol) + fmt.Fprintf(w, "\tif r != %s {\n", want) + fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want) + fmt.Fprintf(w, "\t}\n") + } + } + // signed LHS + for _, c := range ls.i { + fmt.Fprintf(w, "\tx = %d\n", c) + for _, d := range rs.u { + fmt.Fprintf(w, "\ty = %d\n", d) + fmt.Fprintf(w, "\tr = x %s y\n", o.symbol) + want := ansS(c, int64(d), ls.name, o.symbol) + fmt.Fprintf(w, "\tif r != %s {\n", want) + fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want) + fmt.Fprintf(w, "\t}\n") + } + } + fmt.Fprintf(w, "}\n") + } + } + } + // gofmt result + b := w.Bytes() + src, err := format.Source(b) + if err != nil { + fmt.Printf("%s\n", b) + panic(err) + } + + // write to file + err = ioutil.WriteFile("../../constFold_test.go", src, 0666) + if err != nil { + log.Fatalf("can't write output: %v\n", err) + } +} From 824e1f2e083c9c1df8455554744e49471becbaa2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 24 May 2016 12:54:14 -0700 Subject: [PATCH 217/267] text/scanner: better error message if no error handler is installed This is reverting golang.org/cl/19622 and introducing "" as filename if no filename is specified. Fixes #15813. Change-Id: Iafc74b789fa33f48ee639c42d4aebc6f06435f95 Reviewed-on: https://go-review.googlesource.com/23402 Reviewed-by: Russ Cox --- src/text/scanner/example_test.go | 21 +++++------ src/text/scanner/scanner.go | 13 +++---- src/text/scanner/scanner_test.go | 62 ++++++++++++++++---------------- 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/text/scanner/example_test.go b/src/text/scanner/example_test.go index 101145948fac43..1d5d34a0152627 100644 --- a/src/text/scanner/example_test.go +++ b/src/text/scanner/example_test.go @@ -17,6 +17,7 @@ func Example() { someParsable = text }` var s scanner.Scanner + s.Filename = "example" s.Init(strings.NewReader(src)) var tok rune for tok != scanner.EOF { @@ -25,14 +26,14 @@ func Example() { } // Output: - // At position 3:4 : if - // At position 3:6 : a - // At position 3:8 : > - // At position 3:11 : 10 - // At position 3:13 : { - // At position 4:15 : someParsable - // At position 4:17 : = - // At position 4:22 : text - // At position 5:3 : } - // At position 5:3 : + // At position example:3:4 : if + // At position example:3:6 : a + // At position example:3:8 : > + // At position example:3:11 : 10 + // At position example:3:13 : { + // At position example:4:15 : someParsable + // At position example:4:17 : = + // At position example:4:22 : text + // At position example:5:3 : } + // At position example:5:3 : } diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go index a3da1fdabf4455..e085f8a7d956bb 100644 --- a/src/text/scanner/scanner.go +++ b/src/text/scanner/scanner.go @@ -37,14 +37,11 @@ func (pos *Position) IsValid() bool { return pos.Line > 0 } func (pos Position) String() string { s := pos.Filename - if pos.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", pos.Line, pos.Column) - } if s == "" { - s = "???" + s = "" + } + if pos.IsValid() { + s += fmt.Sprintf(":%d:%d", pos.Line, pos.Column) } return s } @@ -333,7 +330,7 @@ func (s *Scanner) error(msg string) { if !pos.IsValid() { pos = s.Pos() } - fmt.Fprintf(os.Stderr, "text/scanner: %s: %s\n", pos, msg) + fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) } func (s *Scanner) isIdentRune(ch rune, i int) bool { diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go index 798bed7e92aa0a..3e92d659ca029e 100644 --- a/src/text/scanner/scanner_test.go +++ b/src/text/scanner/scanner_test.go @@ -451,37 +451,37 @@ func testError(t *testing.T, src, pos, msg string, tok rune) { } func TestError(t *testing.T) { - testError(t, "\x00", "1:1", "illegal character NUL", 0) - testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError) - testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError) - - testError(t, "a\x00", "1:2", "illegal character NUL", Ident) - testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident) - testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident) - - testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String) - testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String) - testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String) - - testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String) - testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String) - testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String) - - testError(t, `'\"'`, "1:3", "illegal char escape", Char) - testError(t, `"\'"`, "1:3", "illegal char escape", String) - - testError(t, `01238`, "1:6", "illegal octal number", Int) - testError(t, `01238123`, "1:9", "illegal octal number", Int) - testError(t, `0x`, "1:3", "illegal hexadecimal number", Int) - testError(t, `0xg`, "1:3", "illegal hexadecimal number", Int) - testError(t, `'aa'`, "1:4", "illegal char literal", Char) - - testError(t, `'`, "1:2", "literal not terminated", Char) - testError(t, `'`+"\n", "1:2", "literal not terminated", Char) - testError(t, `"abc`, "1:5", "literal not terminated", String) - testError(t, `"abc`+"\n", "1:5", "literal not terminated", String) - testError(t, "`abc\n", "2:1", "literal not terminated", String) - testError(t, `/*/`, "1:4", "comment not terminated", EOF) + testError(t, "\x00", ":1:1", "illegal character NUL", 0) + testError(t, "\x80", ":1:1", "illegal UTF-8 encoding", utf8.RuneError) + testError(t, "\xff", ":1:1", "illegal UTF-8 encoding", utf8.RuneError) + + testError(t, "a\x00", ":1:2", "illegal character NUL", Ident) + testError(t, "ab\x80", ":1:3", "illegal UTF-8 encoding", Ident) + testError(t, "abc\xff", ":1:4", "illegal UTF-8 encoding", Ident) + + testError(t, `"a`+"\x00", ":1:3", "illegal character NUL", String) + testError(t, `"ab`+"\x80", ":1:4", "illegal UTF-8 encoding", String) + testError(t, `"abc`+"\xff", ":1:5", "illegal UTF-8 encoding", String) + + testError(t, "`a"+"\x00", ":1:3", "illegal character NUL", String) + testError(t, "`ab"+"\x80", ":1:4", "illegal UTF-8 encoding", String) + testError(t, "`abc"+"\xff", ":1:5", "illegal UTF-8 encoding", String) + + testError(t, `'\"'`, ":1:3", "illegal char escape", Char) + testError(t, `"\'"`, ":1:3", "illegal char escape", String) + + testError(t, `01238`, ":1:6", "illegal octal number", Int) + testError(t, `01238123`, ":1:9", "illegal octal number", Int) + testError(t, `0x`, ":1:3", "illegal hexadecimal number", Int) + testError(t, `0xg`, ":1:3", "illegal hexadecimal number", Int) + testError(t, `'aa'`, ":1:4", "illegal char literal", Char) + + testError(t, `'`, ":1:2", "literal not terminated", Char) + testError(t, `'`+"\n", ":1:2", "literal not terminated", Char) + testError(t, `"abc`, ":1:5", "literal not terminated", String) + testError(t, `"abc`+"\n", ":1:5", "literal not terminated", String) + testError(t, "`abc\n", ":2:1", "literal not terminated", String) + testError(t, `/*/`, ":1:4", "comment not terminated", EOF) } // An errReader returns (0, err) where err is not io.EOF. From 095fbdcc91e41abf52a690dd6c64d701682ca96b Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 15:44:39 +0200 Subject: [PATCH 218/267] runtime: use of Run for some benchmarks Names of sub-benchmarks are preserved, short of the additional slash. Change-Id: I9b3f82964f9a44b0d28724413320afd091ed3106 Reviewed-on: https://go-review.googlesource.com/23425 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot --- src/runtime/memmove_test.go | 189 ++++++++++++------------------------ 1 file changed, 64 insertions(+), 125 deletions(-) diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go index 8bf0c65e298329..2124cb9d499d50 100644 --- a/src/runtime/memmove_test.go +++ b/src/runtime/memmove_test.go @@ -5,6 +5,7 @@ package runtime_test import ( + "fmt" . "runtime" "testing" ) @@ -81,110 +82,49 @@ func TestMemmoveAlias(t *testing.T) { } } -func bmMemmove(b *testing.B, n int) { - x := make([]byte, n) - y := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - copy(x, y) +func benchmarkSizes(b *testing.B, sizes []int, fn func(b *testing.B, n int)) { + for _, n := range sizes { + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n)) + fn(b, n) + }) } } -func BenchmarkMemmove0(b *testing.B) { bmMemmove(b, 0) } -func BenchmarkMemmove1(b *testing.B) { bmMemmove(b, 1) } -func BenchmarkMemmove2(b *testing.B) { bmMemmove(b, 2) } -func BenchmarkMemmove3(b *testing.B) { bmMemmove(b, 3) } -func BenchmarkMemmove4(b *testing.B) { bmMemmove(b, 4) } -func BenchmarkMemmove5(b *testing.B) { bmMemmove(b, 5) } -func BenchmarkMemmove6(b *testing.B) { bmMemmove(b, 6) } -func BenchmarkMemmove7(b *testing.B) { bmMemmove(b, 7) } -func BenchmarkMemmove8(b *testing.B) { bmMemmove(b, 8) } -func BenchmarkMemmove9(b *testing.B) { bmMemmove(b, 9) } -func BenchmarkMemmove10(b *testing.B) { bmMemmove(b, 10) } -func BenchmarkMemmove11(b *testing.B) { bmMemmove(b, 11) } -func BenchmarkMemmove12(b *testing.B) { bmMemmove(b, 12) } -func BenchmarkMemmove13(b *testing.B) { bmMemmove(b, 13) } -func BenchmarkMemmove14(b *testing.B) { bmMemmove(b, 14) } -func BenchmarkMemmove15(b *testing.B) { bmMemmove(b, 15) } -func BenchmarkMemmove16(b *testing.B) { bmMemmove(b, 16) } -func BenchmarkMemmove32(b *testing.B) { bmMemmove(b, 32) } -func BenchmarkMemmove64(b *testing.B) { bmMemmove(b, 64) } -func BenchmarkMemmove128(b *testing.B) { bmMemmove(b, 128) } -func BenchmarkMemmove256(b *testing.B) { bmMemmove(b, 256) } -func BenchmarkMemmove512(b *testing.B) { bmMemmove(b, 512) } -func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) } -func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) } -func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) } - -func bmMemmoveUnalignedDst(b *testing.B, n int) { - x := make([]byte, n+1) - y := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - copy(x[1:], y) - } +var bufSizes = []int{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 32, 64, 128, 256, 512, 1024, 2048, 4096, } -func BenchmarkMemmoveUnalignedDst0(b *testing.B) { bmMemmoveUnalignedDst(b, 0) } -func BenchmarkMemmoveUnalignedDst1(b *testing.B) { bmMemmoveUnalignedDst(b, 1) } -func BenchmarkMemmoveUnalignedDst2(b *testing.B) { bmMemmoveUnalignedDst(b, 2) } -func BenchmarkMemmoveUnalignedDst3(b *testing.B) { bmMemmoveUnalignedDst(b, 3) } -func BenchmarkMemmoveUnalignedDst4(b *testing.B) { bmMemmoveUnalignedDst(b, 4) } -func BenchmarkMemmoveUnalignedDst5(b *testing.B) { bmMemmoveUnalignedDst(b, 5) } -func BenchmarkMemmoveUnalignedDst6(b *testing.B) { bmMemmoveUnalignedDst(b, 6) } -func BenchmarkMemmoveUnalignedDst7(b *testing.B) { bmMemmoveUnalignedDst(b, 7) } -func BenchmarkMemmoveUnalignedDst8(b *testing.B) { bmMemmoveUnalignedDst(b, 8) } -func BenchmarkMemmoveUnalignedDst9(b *testing.B) { bmMemmoveUnalignedDst(b, 9) } -func BenchmarkMemmoveUnalignedDst10(b *testing.B) { bmMemmoveUnalignedDst(b, 10) } -func BenchmarkMemmoveUnalignedDst11(b *testing.B) { bmMemmoveUnalignedDst(b, 11) } -func BenchmarkMemmoveUnalignedDst12(b *testing.B) { bmMemmoveUnalignedDst(b, 12) } -func BenchmarkMemmoveUnalignedDst13(b *testing.B) { bmMemmoveUnalignedDst(b, 13) } -func BenchmarkMemmoveUnalignedDst14(b *testing.B) { bmMemmoveUnalignedDst(b, 14) } -func BenchmarkMemmoveUnalignedDst15(b *testing.B) { bmMemmoveUnalignedDst(b, 15) } -func BenchmarkMemmoveUnalignedDst16(b *testing.B) { bmMemmoveUnalignedDst(b, 16) } -func BenchmarkMemmoveUnalignedDst32(b *testing.B) { bmMemmoveUnalignedDst(b, 32) } -func BenchmarkMemmoveUnalignedDst64(b *testing.B) { bmMemmoveUnalignedDst(b, 64) } -func BenchmarkMemmoveUnalignedDst128(b *testing.B) { bmMemmoveUnalignedDst(b, 128) } -func BenchmarkMemmoveUnalignedDst256(b *testing.B) { bmMemmoveUnalignedDst(b, 256) } -func BenchmarkMemmoveUnalignedDst512(b *testing.B) { bmMemmoveUnalignedDst(b, 512) } -func BenchmarkMemmoveUnalignedDst1024(b *testing.B) { bmMemmoveUnalignedDst(b, 1024) } -func BenchmarkMemmoveUnalignedDst2048(b *testing.B) { bmMemmoveUnalignedDst(b, 2048) } -func BenchmarkMemmoveUnalignedDst4096(b *testing.B) { bmMemmoveUnalignedDst(b, 4096) } +func BenchmarkMemmove(b *testing.B) { + benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { + x := make([]byte, n) + y := make([]byte, n) + for i := 0; i < b.N; i++ { + copy(x, y) + } + }) +} -func bmMemmoveUnalignedSrc(b *testing.B, n int) { - x := make([]byte, n) - y := make([]byte, n+1) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - copy(x, y[1:]) - } +func BenchmarkMemmoveUnalignedDst(b *testing.B) { + benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { + x := make([]byte, n+1) + y := make([]byte, n) + for i := 0; i < b.N; i++ { + copy(x[1:], y) + } + }) } -func BenchmarkMemmoveUnalignedSrc0(b *testing.B) { bmMemmoveUnalignedSrc(b, 0) } -func BenchmarkMemmoveUnalignedSrc1(b *testing.B) { bmMemmoveUnalignedSrc(b, 1) } -func BenchmarkMemmoveUnalignedSrc2(b *testing.B) { bmMemmoveUnalignedSrc(b, 2) } -func BenchmarkMemmoveUnalignedSrc3(b *testing.B) { bmMemmoveUnalignedSrc(b, 3) } -func BenchmarkMemmoveUnalignedSrc4(b *testing.B) { bmMemmoveUnalignedSrc(b, 4) } -func BenchmarkMemmoveUnalignedSrc5(b *testing.B) { bmMemmoveUnalignedSrc(b, 5) } -func BenchmarkMemmoveUnalignedSrc6(b *testing.B) { bmMemmoveUnalignedSrc(b, 6) } -func BenchmarkMemmoveUnalignedSrc7(b *testing.B) { bmMemmoveUnalignedSrc(b, 7) } -func BenchmarkMemmoveUnalignedSrc8(b *testing.B) { bmMemmoveUnalignedSrc(b, 8) } -func BenchmarkMemmoveUnalignedSrc9(b *testing.B) { bmMemmoveUnalignedSrc(b, 9) } -func BenchmarkMemmoveUnalignedSrc10(b *testing.B) { bmMemmoveUnalignedSrc(b, 10) } -func BenchmarkMemmoveUnalignedSrc11(b *testing.B) { bmMemmoveUnalignedSrc(b, 11) } -func BenchmarkMemmoveUnalignedSrc12(b *testing.B) { bmMemmoveUnalignedSrc(b, 12) } -func BenchmarkMemmoveUnalignedSrc13(b *testing.B) { bmMemmoveUnalignedSrc(b, 13) } -func BenchmarkMemmoveUnalignedSrc14(b *testing.B) { bmMemmoveUnalignedSrc(b, 14) } -func BenchmarkMemmoveUnalignedSrc15(b *testing.B) { bmMemmoveUnalignedSrc(b, 15) } -func BenchmarkMemmoveUnalignedSrc16(b *testing.B) { bmMemmoveUnalignedSrc(b, 16) } -func BenchmarkMemmoveUnalignedSrc32(b *testing.B) { bmMemmoveUnalignedSrc(b, 32) } -func BenchmarkMemmoveUnalignedSrc64(b *testing.B) { bmMemmoveUnalignedSrc(b, 64) } -func BenchmarkMemmoveUnalignedSrc128(b *testing.B) { bmMemmoveUnalignedSrc(b, 128) } -func BenchmarkMemmoveUnalignedSrc256(b *testing.B) { bmMemmoveUnalignedSrc(b, 256) } -func BenchmarkMemmoveUnalignedSrc512(b *testing.B) { bmMemmoveUnalignedSrc(b, 512) } -func BenchmarkMemmoveUnalignedSrc1024(b *testing.B) { bmMemmoveUnalignedSrc(b, 1024) } -func BenchmarkMemmoveUnalignedSrc2048(b *testing.B) { bmMemmoveUnalignedSrc(b, 2048) } -func BenchmarkMemmoveUnalignedSrc4096(b *testing.B) { bmMemmoveUnalignedSrc(b, 4096) } +func BenchmarkMemmoveUnalignedSrc(b *testing.B) { + benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { + x := make([]byte, n) + y := make([]byte, n+1) + for i := 0; i < b.N; i++ { + copy(x, y[1:]) + } + }) +} func TestMemclr(t *testing.T) { size := 512 @@ -218,38 +158,37 @@ func TestMemclr(t *testing.T) { } } -func bmMemclr(b *testing.B, n int) { - x := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - MemclrBytes(x) - } -} -func BenchmarkMemclr5(b *testing.B) { bmMemclr(b, 5) } -func BenchmarkMemclr16(b *testing.B) { bmMemclr(b, 16) } -func BenchmarkMemclr64(b *testing.B) { bmMemclr(b, 64) } -func BenchmarkMemclr256(b *testing.B) { bmMemclr(b, 256) } -func BenchmarkMemclr4096(b *testing.B) { bmMemclr(b, 4096) } -func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) } -func BenchmarkMemclr1M(b *testing.B) { bmMemclr(b, 1<<20) } -func BenchmarkMemclr4M(b *testing.B) { bmMemclr(b, 4<<20) } -func BenchmarkMemclr8M(b *testing.B) { bmMemclr(b, 8<<20) } -func BenchmarkMemclr16M(b *testing.B) { bmMemclr(b, 16<<20) } -func BenchmarkMemclr64M(b *testing.B) { bmMemclr(b, 64<<20) } +func BenchmarkMemclr(b *testing.B) { + for _, n := range []int{5, 16, 64, 256, 4096, 65536} { + x := make([]byte, n) + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n)) + for i := 0; i < b.N; i++ { + MemclrBytes(x) + } + }) + } + for _, m := range []int{1, 4, 8, 16, 64} { + x := make([]byte, m<<20) + b.Run(fmt.Sprint(m, "M"), func(b *testing.B) { + b.SetBytes(int64(m << 20)) + for i := 0; i < b.N; i++ { + MemclrBytes(x) + } + }) + } +} -func bmGoMemclr(b *testing.B, n int) { - x := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - for j := range x { - x[j] = 0 +func BenchmarkGoMemclr(b *testing.B) { + benchmarkSizes(b, []int{5, 16, 64, 256}, func(b *testing.B, n int) { + x := make([]byte, n) + for i := 0; i < b.N; i++ { + for j := range x { + x[j] = 0 + } } - } + }) } -func BenchmarkGoMemclr5(b *testing.B) { bmGoMemclr(b, 5) } -func BenchmarkGoMemclr16(b *testing.B) { bmGoMemclr(b, 16) } -func BenchmarkGoMemclr64(b *testing.B) { bmGoMemclr(b, 64) } -func BenchmarkGoMemclr256(b *testing.B) { bmGoMemclr(b, 256) } func BenchmarkClearFat8(b *testing.B) { for i := 0; i < b.N; i++ { From 5dd922c935d28ded082f76a81e0c963938d7c3c3 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 14:54:41 +0200 Subject: [PATCH 219/267] compress/lzw: use Run for benchmarks load file only once per group. Change-Id: I965661507055e6e100506bf14d37133ecdd2cc5e Reviewed-on: https://go-review.googlesource.com/23423 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot --- src/compress/lzw/reader_test.go | 61 ++++++++++++++++----------------- src/compress/lzw/writer_test.go | 55 ++++++++++++++--------------- 2 files changed, 54 insertions(+), 62 deletions(-) diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go index c3a5c3a0aaacdf..6b9f9a3da7035d 100644 --- a/src/compress/lzw/reader_test.go +++ b/src/compress/lzw/reader_test.go @@ -6,8 +6,10 @@ package lzw import ( "bytes" + "fmt" "io" "io/ioutil" + "math" "runtime" "strconv" "strings" @@ -118,42 +120,37 @@ func TestReader(t *testing.T) { } } -func benchmarkDecoder(b *testing.B, n int) { - b.StopTimer() - b.SetBytes(int64(n)) - buf0, err := ioutil.ReadFile("../testdata/e.txt") +func BenchmarkDecoder(b *testing.B) { + buf, err := ioutil.ReadFile("../testdata/e.txt") if err != nil { b.Fatal(err) } - if len(buf0) == 0 { + if len(buf) == 0 { b.Fatalf("test file has no data") } - compressed := new(bytes.Buffer) - w := NewWriter(compressed, LSB, 8) - for i := 0; i < n; i += len(buf0) { - if len(buf0) > n-i { - buf0 = buf0[:n-i] - } - w.Write(buf0) - } - w.Close() - buf1 := compressed.Bytes() - buf0, compressed, w = nil, nil, nil - runtime.GC() - b.StartTimer() - for i := 0; i < b.N; i++ { - io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8)) - } -} - -func BenchmarkDecoder1e4(b *testing.B) { - benchmarkDecoder(b, 1e4) -} -func BenchmarkDecoder1e5(b *testing.B) { - benchmarkDecoder(b, 1e5) -} - -func BenchmarkDecoder1e6(b *testing.B) { - benchmarkDecoder(b, 1e6) + for e := 4; e <= 6; e++ { + n := int(math.Pow10(e)) + b.Run(fmt.Sprint("1e", e), func(b *testing.B) { + b.StopTimer() + b.SetBytes(int64(n)) + buf0 := buf + compressed := new(bytes.Buffer) + w := NewWriter(compressed, LSB, 8) + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + w.Write(buf0) + } + w.Close() + buf1 := compressed.Bytes() + buf0, compressed, w = nil, nil, nil + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8)) + } + }) + } } diff --git a/src/compress/lzw/writer_test.go b/src/compress/lzw/writer_test.go index 66d761727f481d..4979f8b3521139 100644 --- a/src/compress/lzw/writer_test.go +++ b/src/compress/lzw/writer_test.go @@ -5,9 +5,11 @@ package lzw import ( + "fmt" "internal/testenv" "io" "io/ioutil" + "math" "os" "runtime" "testing" @@ -122,41 +124,34 @@ func TestSmallLitWidth(t *testing.T) { } } -func benchmarkEncoder(b *testing.B, n int) { - b.StopTimer() - b.SetBytes(int64(n)) - buf0, err := ioutil.ReadFile("../testdata/e.txt") +func BenchmarkEncoder(b *testing.B) { + buf, err := ioutil.ReadFile("../testdata/e.txt") if err != nil { b.Fatal(err) } - if len(buf0) == 0 { + if len(buf) == 0 { b.Fatalf("test file has no data") } - buf1 := make([]byte, n) - for i := 0; i < n; i += len(buf0) { - if len(buf0) > n-i { - buf0 = buf0[:n-i] + + for e := 4; e <= 6; e++ { + n := int(math.Pow10(e)) + buf0 := buf + buf1 := make([]byte, n) + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + copy(buf1[i:], buf0) } - copy(buf1[i:], buf0) - } - buf0 = nil - runtime.GC() - b.StartTimer() - for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, LSB, 8) - w.Write(buf1) - w.Close() + buf0 = nil + runtime.GC() + b.Run(fmt.Sprint("1e", e), func(b *testing.B) { + b.SetBytes(int64(n)) + for i := 0; i < b.N; i++ { + w := NewWriter(ioutil.Discard, LSB, 8) + w.Write(buf1) + w.Close() + } + }) } } - -func BenchmarkEncoder1e4(b *testing.B) { - benchmarkEncoder(b, 1e4) -} - -func BenchmarkEncoder1e5(b *testing.B) { - benchmarkEncoder(b, 1e5) -} - -func BenchmarkEncoder1e6(b *testing.B) { - benchmarkEncoder(b, 1e6) -} From 89283781c69314f09e999fe131b12c57059c1ba1 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Tue, 24 May 2016 20:03:31 +0200 Subject: [PATCH 220/267] testing: added package doc for sub(tests/benchmarks) Change-Id: I6991cd7a41140da784a1ff8d69c5ea2032d05850 Reviewed-on: https://go-review.googlesource.com/23354 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot --- src/testing/testing.go | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/testing/testing.go b/src/testing/testing.go index 9943fa6b4d8c21..657a7b731fabe6 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -118,6 +118,61 @@ // example function, at least one other function, type, variable, or constant // declaration, and no test or benchmark functions. // +// Subtests and Sub-benchmarks +// +// The Run methods of T and B allow defining subtests and sub-benchmarks, +// without having to define separate functions for each. This enables uses +// like table-driven benchmarks and creating hierarchical tests. +// It also provides a way to share common setup and tear-down code: +// +// func TestFoo(t *testing.T) { +// // +// t.Run("A=1", func(t *testing.T) { ... }) +// t.Run("A=2", func(t *testing.T) { ... }) +// t.Run("B=1", func(t *testing.T) { ... }) +// // +// } +// +// Each subtest and sub-benchmark has a unique name: the combination of the name +// of the top-level test and the sequence of names passed to Run, separated by +// slashes, with an optional trailing sequence number for disambiguation. +// +// The argument to the -run and -bench command-line flags is a slash-separated +// list of regular expressions that match each name element in turn. +// For example: +// +// go test -run Foo # Run top-level tests matching "Foo". +// go test -run Foo/A= # Run subtests of Foo matching "A=". +// go test -run /A=1 # Run all subtests of a top-level test matching "A=1". +// +// Subtests can also be used to control parallelism. A parent test will only +// complete once all of its subtests complete. In this example, all tests are +// run in parallel with each other, and only with each other, regardless of +// other top-level tests that may be defined: +// +// func TestGroupedParallel(t *testing.T) { +// for _, tc := range tests { +// tc := tc // capture range variable +// t.Run(tc.Name, func(t *testing.T) { +// t.Parallel() +// ... +// }) +// } +// } +// +// Run does not return until parallel subtests have completed, providing a way +// to clean up after a group of parallel tests: +// +// func TestTeardownParallel(t *testing.T) { +// // This Run will not return until the parallel tests finish. +// t.Run("group", func(t *testing.T) { +// t.Run("Test1", parallelTest1) +// t.Run("Test2", parallelTest2) +// t.Run("Test3", parallelTest3) +// }) +// // +// } +// // Main // // It is sometimes necessary for a test program to do extra setup or teardown From d2aa5f95cce5055d71a77166a60b574cd3f8ecd5 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 11:19:17 +0200 Subject: [PATCH 221/267] compress/flate: simplify using subtests and sub-benchmarks This causes the large files to be loaded only once per benchmark. This CL also serves as an example use case of sub(tests|-benchmarks). This CL ensures that names are identical to the original except for an added slashes. Things could be simplified further if this restriction were dropped. Change-Id: I45e303e158e3152e33d0d751adfef784713bf997 Reviewed-on: https://go-review.googlesource.com/23420 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen Reviewed-by: Joe Tsai TryBot-Result: Gobot Gobot --- src/compress/flate/reader_test.go | 133 ++++++++++++++---------------- src/compress/flate/writer_test.go | 94 +++++++-------------- 2 files changed, 94 insertions(+), 133 deletions(-) diff --git a/src/compress/flate/reader_test.go b/src/compress/flate/reader_test.go index b336278c07d015..b0a16ce18b98d6 100644 --- a/src/compress/flate/reader_test.go +++ b/src/compress/flate/reader_test.go @@ -22,82 +22,77 @@ func TestNlitOutOfRange(t *testing.T) { "\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c"))) } -const ( - digits = iota - twain -) - -var testfiles = []string{ +var suites = []struct{ name, file string }{ // Digits is the digits of the irrational number e. Its decimal representation // does not repeat, but there are only 10 possible digits, so it should be // reasonably compressible. - digits: "../testdata/e.txt", + {"Digits", "../testdata/e.txt"}, // Twain is Mark Twain's classic English novel. - twain: "../testdata/Mark.Twain-Tom.Sawyer.txt", + {"Twain", "../testdata/Mark.Twain-Tom.Sawyer.txt"}, } -func benchmarkDecode(b *testing.B, testfile, level, n int) { - b.ReportAllocs() - b.StopTimer() - b.SetBytes(int64(n)) - buf0, err := ioutil.ReadFile(testfiles[testfile]) - if err != nil { - b.Fatal(err) - } - if len(buf0) == 0 { - b.Fatalf("test file %q has no data", testfiles[testfile]) - } - compressed := new(bytes.Buffer) - w, err := NewWriter(compressed, level) - if err != nil { - b.Fatal(err) - } - for i := 0; i < n; i += len(buf0) { - if len(buf0) > n-i { - buf0 = buf0[:n-i] +func BenchmarkDecode(b *testing.B) { + doBench(b, func(b *testing.B, buf0 []byte, level, n int) { + b.ReportAllocs() + b.StopTimer() + b.SetBytes(int64(n)) + + compressed := new(bytes.Buffer) + w, err := NewWriter(compressed, level) + if err != nil { + b.Fatal(err) } - io.Copy(w, bytes.NewReader(buf0)) - } - w.Close() - buf1 := compressed.Bytes() - buf0, compressed, w = nil, nil, nil - runtime.GC() - b.StartTimer() - for i := 0; i < b.N; i++ { - io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1))) - } + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + io.Copy(w, bytes.NewReader(buf0)) + } + w.Close() + buf1 := compressed.Bytes() + buf0, compressed, w = nil, nil, nil + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1))) + } + }) } -// These short names are so that gofmt doesn't break the BenchmarkXxx function -// bodies below over multiple lines. -const ( - speed = BestSpeed - default_ = DefaultCompression - compress = BestCompression - huffman = HuffmanOnly -) +var levelTests = []struct { + name string + level int +}{ + {"Huffman", HuffmanOnly}, + {"Speed", BestSpeed}, + {"Default", DefaultCompression}, + {"Compression", BestCompression}, +} -func BenchmarkDecodeDigitsHuffman1e4(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e4) } -func BenchmarkDecodeDigitsHuffman1e5(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e5) } -func BenchmarkDecodeDigitsHuffman1e6(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e6) } -func BenchmarkDecodeDigitsSpeed1e4(b *testing.B) { benchmarkDecode(b, digits, speed, 1e4) } -func BenchmarkDecodeDigitsSpeed1e5(b *testing.B) { benchmarkDecode(b, digits, speed, 1e5) } -func BenchmarkDecodeDigitsSpeed1e6(b *testing.B) { benchmarkDecode(b, digits, speed, 1e6) } -func BenchmarkDecodeDigitsDefault1e4(b *testing.B) { benchmarkDecode(b, digits, default_, 1e4) } -func BenchmarkDecodeDigitsDefault1e5(b *testing.B) { benchmarkDecode(b, digits, default_, 1e5) } -func BenchmarkDecodeDigitsDefault1e6(b *testing.B) { benchmarkDecode(b, digits, default_, 1e6) } -func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) } -func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) } -func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) } -func BenchmarkDecodeTwainHuffman1e4(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e4) } -func BenchmarkDecodeTwainHuffman1e5(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e5) } -func BenchmarkDecodeTwainHuffman1e6(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e6) } -func BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) } -func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) } -func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) } -func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) } -func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) } -func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) } -func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) } -func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) } -func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) } +var sizes = []struct { + name string + n int +}{ + {"1e4", 1e4}, + {"1e5", 1e5}, + {"1e6", 1e6}, +} + +func doBench(b *testing.B, f func(b *testing.B, buf []byte, level, n int)) { + for _, suite := range suites { + buf, err := ioutil.ReadFile(suite.file) + if err != nil { + b.Fatal(err) + } + if len(buf) == 0 { + b.Fatalf("test file %q has no data", suite.file) + } + for _, l := range levelTests { + for _, s := range sizes { + b.Run(suite.name+"/"+l.name+"/"+s.name, func(b *testing.B) { + f(b, buf, l.level, s.n) + }) + } + } + } +} diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go index 7967cd739c5862..21cd0b22eef5fe 100644 --- a/src/compress/flate/writer_test.go +++ b/src/compress/flate/writer_test.go @@ -14,62 +14,33 @@ import ( "testing" ) -func benchmarkEncoder(b *testing.B, testfile, level, n int) { - b.StopTimer() - b.SetBytes(int64(n)) - buf0, err := ioutil.ReadFile(testfiles[testfile]) - if err != nil { - b.Fatal(err) - } - if len(buf0) == 0 { - b.Fatalf("test file %q has no data", testfiles[testfile]) - } - buf1 := make([]byte, n) - for i := 0; i < n; i += len(buf0) { - if len(buf0) > n-i { - buf0 = buf0[:n-i] +func BenchmarkEncode(b *testing.B) { + doBench(b, func(b *testing.B, buf0 []byte, level, n int) { + b.StopTimer() + b.SetBytes(int64(n)) + + buf1 := make([]byte, n) + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + copy(buf1[i:], buf0) } - copy(buf1[i:], buf0) - } - buf0 = nil - w, err := NewWriter(ioutil.Discard, level) - if err != nil { - b.Fatal(err) - } - runtime.GC() - b.StartTimer() - for i := 0; i < b.N; i++ { - w.Reset(ioutil.Discard) - w.Write(buf1) - w.Close() - } + buf0 = nil + w, err := NewWriter(ioutil.Discard, level) + if err != nil { + b.Fatal(err) + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + w.Reset(ioutil.Discard) + w.Write(buf1) + w.Close() + } + }) } -func BenchmarkEncodeDigitsHuffman1e4(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e4) } -func BenchmarkEncodeDigitsHuffman1e5(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e5) } -func BenchmarkEncodeDigitsHuffman1e6(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e6) } -func BenchmarkEncodeDigitsSpeed1e4(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e4) } -func BenchmarkEncodeDigitsSpeed1e5(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e5) } -func BenchmarkEncodeDigitsSpeed1e6(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e6) } -func BenchmarkEncodeDigitsDefault1e4(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e4) } -func BenchmarkEncodeDigitsDefault1e5(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e5) } -func BenchmarkEncodeDigitsDefault1e6(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e6) } -func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) } -func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) } -func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) } -func BenchmarkEncodeTwainHuffman1e4(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e4) } -func BenchmarkEncodeTwainHuffman1e5(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e5) } -func BenchmarkEncodeTwainHuffman1e6(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e6) } -func BenchmarkEncodeTwainSpeed1e4(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e4) } -func BenchmarkEncodeTwainSpeed1e5(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e5) } -func BenchmarkEncodeTwainSpeed1e6(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e6) } -func BenchmarkEncodeTwainDefault1e4(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e4) } -func BenchmarkEncodeTwainDefault1e5(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e5) } -func BenchmarkEncodeTwainDefault1e6(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e6) } -func BenchmarkEncodeTwainCompress1e4(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e4) } -func BenchmarkEncodeTwainCompress1e5(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e5) } -func BenchmarkEncodeTwainCompress1e6(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e6) } - // errorWriter is a writer that fails after N writes. type errorWriter struct { N int @@ -141,17 +112,12 @@ func TestWriteError(t *testing.T) { // Test if two runs produce identical results // even when writing different sizes to the Writer. -func TestDeterministicL0(t *testing.T) { testDeterministic(0, t) } -func TestDeterministicL1(t *testing.T) { testDeterministic(1, t) } -func TestDeterministicL2(t *testing.T) { testDeterministic(2, t) } -func TestDeterministicL3(t *testing.T) { testDeterministic(3, t) } -func TestDeterministicL4(t *testing.T) { testDeterministic(4, t) } -func TestDeterministicL5(t *testing.T) { testDeterministic(5, t) } -func TestDeterministicL6(t *testing.T) { testDeterministic(6, t) } -func TestDeterministicL7(t *testing.T) { testDeterministic(7, t) } -func TestDeterministicL8(t *testing.T) { testDeterministic(8, t) } -func TestDeterministicL9(t *testing.T) { testDeterministic(9, t) } -func TestDeterministicLM2(t *testing.T) { testDeterministic(-2, t) } +func TestDeterministic(t *testing.T) { + for i := 0; i <= 9; i++ { + t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) }) + } + t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) }) +} func testDeterministic(i int, t *testing.T) { // Test so much we cross a good number of block boundaries. From 23cb8864b52e5f2f60618a551ca564574e0575b0 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 19:34:01 +0200 Subject: [PATCH 222/267] runtime: use Run for more benchmarks Names for Append?Bytes are slightly changed in addition to adding a slash. Change-Id: I0291aa29c693f9040fd01368eaad9766259677df Reviewed-on: https://go-review.googlesource.com/23426 Run-TryBot: Marcel van Lohuizen Reviewed-by: Russ Cox TryBot-Result: Gobot Gobot --- src/runtime/append_test.go | 149 ++++++++++++------------------------- 1 file changed, 48 insertions(+), 101 deletions(-) diff --git a/src/runtime/append_test.go b/src/runtime/append_test.go index cd28e3dca6933c..6b8968e382d349 100644 --- a/src/runtime/append_test.go +++ b/src/runtime/append_test.go @@ -3,7 +3,10 @@ // license that can be found in the LICENSE file. package runtime_test -import "testing" +import ( + "fmt" + "testing" +) const N = 20 @@ -84,75 +87,37 @@ func BenchmarkAppendGrowString(b *testing.B) { } } -func benchmarkAppendBytes(b *testing.B, length int) { - b.StopTimer() - x := make([]byte, 0, N) - y := make([]byte, length) - b.StartTimer() - for i := 0; i < b.N; i++ { - x = x[0:0] - x = append(x, y...) +func BenchmarkAppendSlice(b *testing.B) { + for _, length := range []int{1, 4, 7, 8, 15, 16, 32} { + b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) { + x := make([]byte, 0, N) + y := make([]byte, length) + for i := 0; i < b.N; i++ { + x = x[0:0] + x = append(x, y...) + } + }) } } -func BenchmarkAppend1Byte(b *testing.B) { - benchmarkAppendBytes(b, 1) -} - -func BenchmarkAppend4Bytes(b *testing.B) { - benchmarkAppendBytes(b, 4) -} - -func BenchmarkAppend7Bytes(b *testing.B) { - benchmarkAppendBytes(b, 7) -} - -func BenchmarkAppend8Bytes(b *testing.B) { - benchmarkAppendBytes(b, 8) -} - -func BenchmarkAppend15Bytes(b *testing.B) { - benchmarkAppendBytes(b, 15) -} - -func BenchmarkAppend16Bytes(b *testing.B) { - benchmarkAppendBytes(b, 16) -} - -func BenchmarkAppend32Bytes(b *testing.B) { - benchmarkAppendBytes(b, 32) -} - -func benchmarkAppendStr(b *testing.B, str string) { - b.StopTimer() - x := make([]byte, 0, N) - b.StartTimer() - for i := 0; i < b.N; i++ { - x = x[0:0] - x = append(x, str...) +func BenchmarkAppendStr(b *testing.B) { + for _, str := range []string{ + "1", + "1234", + "12345678", + "1234567890123456", + "12345678901234567890123456789012", + } { + b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) { + x := make([]byte, 0, N) + for i := 0; i < b.N; i++ { + x = x[0:0] + x = append(x, str...) + } + }) } } -func BenchmarkAppendStr1Byte(b *testing.B) { - benchmarkAppendStr(b, "1") -} - -func BenchmarkAppendStr4Bytes(b *testing.B) { - benchmarkAppendStr(b, "1234") -} - -func BenchmarkAppendStr8Bytes(b *testing.B) { - benchmarkAppendStr(b, "12345678") -} - -func BenchmarkAppendStr16Bytes(b *testing.B) { - benchmarkAppendStr(b, "1234567890123456") -} - -func BenchmarkAppendStr32Bytes(b *testing.B) { - benchmarkAppendStr(b, "12345678901234567890123456789012") -} - func BenchmarkAppendSpecialCase(b *testing.B) { b.StopTimer() x := make([]int, 0, N) @@ -195,46 +160,28 @@ func TestAppendOverlap(t *testing.T) { } } -func benchmarkCopySlice(b *testing.B, l int) { - s := make([]byte, l) - buf := make([]byte, 4096) - var n int - for i := 0; i < b.N; i++ { - n = copy(buf, s) - } - b.SetBytes(int64(n)) -} - -func benchmarkCopyStr(b *testing.B, l int) { - s := string(make([]byte, l)) - buf := make([]byte, 4096) - var n int - for i := 0; i < b.N; i++ { - n = copy(buf, s) +func BenchmarkCopy(b *testing.B) { + for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} { + buf := make([]byte, 4096) + b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) { + s := make([]byte, l) + var n int + for i := 0; i < b.N; i++ { + n = copy(buf, s) + } + b.SetBytes(int64(n)) + }) + b.Run(fmt.Sprint(l, "String"), func(b *testing.B) { + s := string(make([]byte, l)) + var n int + for i := 0; i < b.N; i++ { + n = copy(buf, s) + } + b.SetBytes(int64(n)) + }) } - b.SetBytes(int64(n)) } -func BenchmarkCopy1Byte(b *testing.B) { benchmarkCopySlice(b, 1) } -func BenchmarkCopy2Byte(b *testing.B) { benchmarkCopySlice(b, 2) } -func BenchmarkCopy4Byte(b *testing.B) { benchmarkCopySlice(b, 4) } -func BenchmarkCopy8Byte(b *testing.B) { benchmarkCopySlice(b, 8) } -func BenchmarkCopy12Byte(b *testing.B) { benchmarkCopySlice(b, 12) } -func BenchmarkCopy16Byte(b *testing.B) { benchmarkCopySlice(b, 16) } -func BenchmarkCopy32Byte(b *testing.B) { benchmarkCopySlice(b, 32) } -func BenchmarkCopy128Byte(b *testing.B) { benchmarkCopySlice(b, 128) } -func BenchmarkCopy1024Byte(b *testing.B) { benchmarkCopySlice(b, 1024) } - -func BenchmarkCopy1String(b *testing.B) { benchmarkCopyStr(b, 1) } -func BenchmarkCopy2String(b *testing.B) { benchmarkCopyStr(b, 2) } -func BenchmarkCopy4String(b *testing.B) { benchmarkCopyStr(b, 4) } -func BenchmarkCopy8String(b *testing.B) { benchmarkCopyStr(b, 8) } -func BenchmarkCopy12String(b *testing.B) { benchmarkCopyStr(b, 12) } -func BenchmarkCopy16String(b *testing.B) { benchmarkCopyStr(b, 16) } -func BenchmarkCopy32String(b *testing.B) { benchmarkCopyStr(b, 32) } -func BenchmarkCopy128String(b *testing.B) { benchmarkCopyStr(b, 128) } -func BenchmarkCopy1024String(b *testing.B) { benchmarkCopyStr(b, 1024) } - var ( sByte []byte s1Ptr []uintptr From 07f0c19a30a5c83592bcd2f19e52eb8a40b32790 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 14:57:49 +0200 Subject: [PATCH 223/267] math/big: use run for benchmarks shortens code and gives an example of the use of Run. Change-Id: I75ffaf762218a589274b4b62e19022e31e805d1b Reviewed-on: https://go-review.googlesource.com/23424 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot --- src/math/big/arith_test.go | 135 +++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 75 deletions(-) diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go index 7d2f69a7511572..94e5f5ca8757e7 100644 --- a/src/math/big/arith_test.go +++ b/src/math/big/arith_test.go @@ -5,6 +5,7 @@ package big import ( + "fmt" "math/rand" "testing" ) @@ -118,28 +119,36 @@ func rndV(n int) []Word { return v } -func benchmarkFunVV(b *testing.B, f funVV, n int) { - x := rndV(n) - y := rndV(n) - z := make([]Word, n) - b.SetBytes(int64(n * _W)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - f(z, x, y) +var benchSizes = []struct { + name string + n int +}{ + {"1", 1}, + {"2", 2}, + {"3", 3}, + {"4", 4}, + {"5", 5}, + {"1e1", 1e1}, + {"1e2", 1e2}, + {"1e3", 1e3}, + {"1e4", 1e4}, + {"1e5", 1e5}, +} + +func BenchmarkAddVV(b *testing.B) { + for _, tc := range benchSizes { + x := rndV(tc.n) + y := rndV(tc.n) + z := make([]Word, tc.n) + b.Run(fmt.Sprint(tc.name), func(b *testing.B) { + b.SetBytes(int64(tc.n * _W)) + for i := 0; i < b.N; i++ { + addVV(z, x, y) + } + }) } } -func BenchmarkAddVV_1(b *testing.B) { benchmarkFunVV(b, addVV, 1) } -func BenchmarkAddVV_2(b *testing.B) { benchmarkFunVV(b, addVV, 2) } -func BenchmarkAddVV_3(b *testing.B) { benchmarkFunVV(b, addVV, 3) } -func BenchmarkAddVV_4(b *testing.B) { benchmarkFunVV(b, addVV, 4) } -func BenchmarkAddVV_5(b *testing.B) { benchmarkFunVV(b, addVV, 5) } -func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) } -func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) } -func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) } -func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) } -func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) } - type funVW func(z, x []Word, y Word) (c Word) type argVW struct { z, x nat @@ -236,28 +245,20 @@ func TestFunVW(t *testing.T) { } } -func benchmarkFunVW(b *testing.B, f funVW, n int) { - x := rndV(n) - y := rndW() - z := make([]Word, n) - b.SetBytes(int64(n * _S)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - f(z, x, y) +func BenchmarkAddVW(b *testing.B) { + for _, tc := range benchSizes { + x := rndV(tc.n) + y := rndW() + z := make([]Word, tc.n) + b.Run(fmt.Sprint(tc.name), func(b *testing.B) { + b.SetBytes(int64(tc.n * _S)) + for i := 0; i < b.N; i++ { + addVW(z, x, y) + } + }) } } -func BenchmarkAddVW_1(b *testing.B) { benchmarkFunVW(b, addVW, 1) } -func BenchmarkAddVW_2(b *testing.B) { benchmarkFunVW(b, addVW, 2) } -func BenchmarkAddVW_3(b *testing.B) { benchmarkFunVW(b, addVW, 3) } -func BenchmarkAddVW_4(b *testing.B) { benchmarkFunVW(b, addVW, 4) } -func BenchmarkAddVW_5(b *testing.B) { benchmarkFunVW(b, addVW, 5) } -func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) } -func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) } -func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) } -func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) } -func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) } - type funVWW func(z, x []Word, y, r Word) (c Word) type argVWW struct { z, x nat @@ -382,28 +383,20 @@ func TestMulAddWWW(t *testing.T) { } } -func benchmarkAddMulVVW(b *testing.B, n int) { - x := rndV(n) - y := rndW() - z := make([]Word, n) - b.SetBytes(int64(n * _W)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - addMulVVW(z, x, y) +func BenchmarkAddMulVVW(b *testing.B) { + for _, tc := range benchSizes { + x := rndV(tc.n) + y := rndW() + z := make([]Word, tc.n) + b.Run(fmt.Sprint(tc.n), func(b *testing.B) { + b.SetBytes(int64(tc.n * _W)) + for i := 0; i < b.N; i++ { + addMulVVW(z, x, y) + } + }) } } -func BenchmarkAddMulVVW_1(b *testing.B) { benchmarkAddMulVVW(b, 1) } -func BenchmarkAddMulVVW_2(b *testing.B) { benchmarkAddMulVVW(b, 2) } -func BenchmarkAddMulVVW_3(b *testing.B) { benchmarkAddMulVVW(b, 3) } -func BenchmarkAddMulVVW_4(b *testing.B) { benchmarkAddMulVVW(b, 4) } -func BenchmarkAddMulVVW_5(b *testing.B) { benchmarkAddMulVVW(b, 5) } -func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) } -func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) } -func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) } -func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) } -func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) } - func testWordBitLen(t *testing.T, fname string, f func(Word) int) { for i := 0; i <= _W; i++ { x := Word(1) << uint(i-1) // i == 0 => x == 0 @@ -420,23 +413,15 @@ func TestWordBitLen(t *testing.T) { } // runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1. -func benchmarkBitLenN(b *testing.B, nbits uint) { - testword := Word((uint64(1) << nbits) - 1) - for i := 0; i < b.N; i++ { - bitLen(testword) +func BenchmarkBitLen(b *testing.B) { + // Individual bitLen tests. Numbers chosen to examine both sides + // of powers-of-two boundaries. + for _, nbits := range []uint{0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 31} { + testword := Word((uint64(1) << nbits) - 1) + b.Run(fmt.Sprint(nbits), func(b *testing.B) { + for i := 0; i < b.N; i++ { + bitLen(testword) + } + }) } } - -// Individual bitLen tests. Numbers chosen to examine both sides -// of powers-of-two boundaries. -func BenchmarkBitLen0(b *testing.B) { benchmarkBitLenN(b, 0) } -func BenchmarkBitLen1(b *testing.B) { benchmarkBitLenN(b, 1) } -func BenchmarkBitLen2(b *testing.B) { benchmarkBitLenN(b, 2) } -func BenchmarkBitLen3(b *testing.B) { benchmarkBitLenN(b, 3) } -func BenchmarkBitLen4(b *testing.B) { benchmarkBitLenN(b, 4) } -func BenchmarkBitLen5(b *testing.B) { benchmarkBitLenN(b, 5) } -func BenchmarkBitLen8(b *testing.B) { benchmarkBitLenN(b, 8) } -func BenchmarkBitLen9(b *testing.B) { benchmarkBitLenN(b, 9) } -func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) } -func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) } -func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) } From b7d96b8e059ce446f25e615ab9ef277eae2ef1c9 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 25 May 2016 08:03:46 -0400 Subject: [PATCH 224/267] doc: reflect {Num,}Method skips unexported methods For #15673 Change-Id: I3ce8d4016854d41860c5a9f05a54cda3de49f337 Reviewed-on: https://go-review.googlesource.com/23430 Reviewed-by: Ian Lance Taylor --- doc/go1.7.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/go1.7.html b/doc/go1.7.html index 74607d7ca5f606..db249dd0531124 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -1049,6 +1049,16 @@

Minor changes to the library

but distinguishes the tag not containing the given key from the tag associating an empty string with the given key.

+ +

+The +Method and +NumMethod +methods of +Type and +Value +no longer return or count unexported methods. +

strings
From a689f6b8af6a1c4a388d6aabb64253e0ce9ab84f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 25 May 2016 11:23:56 -0700 Subject: [PATCH 225/267] cmd/compile: document how to update builtin.go No code changes. Fixes #15835. Change-Id: Ibae3f20882f976babc4093df5e9fea0b2cf0e9d9 Reviewed-on: https://go-review.googlesource.com/23443 Reviewed-by: Alan Donovan --- src/cmd/compile/internal/gc/bexport.go | 41 ++++++++++++++++++++++-- src/cmd/compile/internal/gc/bimport.go | 3 +- src/cmd/compile/internal/gc/mkbuiltin.go | 1 + 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 2e5731e2b8c580..1997068d1af4ef 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -6,7 +6,7 @@ // (see fmt.go, parser.go as "documentation" for how to use/setup data structures) /* -Export data encoding: +1) Export data encoding principles: The export data is a serialized description of the graph of exported "objects": constants, types, variables, and functions. In general, @@ -49,7 +49,7 @@ Before exporting or importing, the type tables are populated with the predeclared types (int, string, error, unsafe.Pointer, etc.). This way they are automatically encoded with a known and fixed type index. -Encoding format: +2) Encoding format: The export data starts with a single byte indicating the encoding format (compact, or with debugging information), followed by a version string @@ -84,6 +84,43 @@ each encoding routine there is a matching and symmetric decoding routine. This symmetry makes it very easy to change or extend the format: If a new field needs to be encoded, a symmetric change can be made to exporter and importer. + +3) Making changes to the encoding format: + +Any change to the encoding format requires a respective change in the +exporter below and a corresponding symmetric change to the importer in +bimport.go. + +Furthermore, it requires a corresponding change to go/internal/gcimporter +and golang.org/x/tools/go/gcimporter15. Changes to the latter must preserve +compatibility with both the last release of the compiler, and with the +corresponding compiler at tip. That change is necessarily more involved, +as it must switch based on the version number in the export data file. + +It is recommended to turn on debugFormat when working on format changes +as it will help finding encoding/decoding inconsistencies quickly. + +Special care must be taken to update builtin.go when the export format +changes: builtin.go contains the export data obtained by compiling the +builtin/runtime.go and builtin/unsafe.go files; those compilations in +turn depend on importing the data in builtin.go. Thus, when the export +data format changes, the compiler must be able to import the data in +builtin.go even if its format has not yet changed. Proceed in several +steps as follows: + +- Change the exporter to use the new format, and use a different version + string as well. +- Update the importer accordingly, but accept both the old and the new + format depending on the version string. +- all.bash should pass at this point. +- Run mkbuiltin.go: this will create a new builtin.go using the new + export format. +- go test -run Builtin should pass at this point. +- Remove importer support for the old export format and (maybe) revert + the version string again (it's only needed to mark the transition). +- all.bash should still pass. + +Don't forget to set debugFormat to false. */ package gc diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index e1885981e04699..b9e69c24bb9a87 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -3,7 +3,8 @@ // license that can be found in the LICENSE file. // Binary package import. -// Based loosely on x/tools/go/importer. +// See bexport.go for the export data format and how +// to make a format change. package gc diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go index eb0e6681fa895d..58cbd240d27584 100644 --- a/src/cmd/compile/internal/gc/mkbuiltin.go +++ b/src/cmd/compile/internal/gc/mkbuiltin.go @@ -8,6 +8,7 @@ // Run this after changing builtin/runtime.go and builtin/unsafe.go // or after changing the export metadata format in the compiler. // Either way, you need to have a working compiler binary first. +// See bexport.go for how to make an export metadata format change. package main import ( From a1f7db88f8c70a7520ce870a71706032f173739f Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 23 May 2016 22:05:51 -0400 Subject: [PATCH 226/267] runtime: document scanstack Also mark it go:systemstack and explain why. Change-Id: I88baf22741c04012ba2588d8e03dd3801d19b5c0 Reviewed-on: https://go-review.googlesource.com/23390 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/mgcmark.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index cbdf2b8375149d..b0e7477d50d9e4 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -642,7 +642,17 @@ func gcFlushBgCredit(scanWork int64) { unlock(&work.assistQueue.lock) } +// scanstack scans gp's stack, greying all pointers found on the stack. +// +// During mark phase, it also installs stack barriers while traversing +// gp's stack. During mark termination, it stops scanning when it +// reaches an unhit stack barrier. +// +// scanstack is marked go:systemstack because it must not be preempted +// while using a workbuf. +// //go:nowritebarrier +//go:systemstack func scanstack(gp *g) { if gp.gcscanvalid { return From 3be48b4dc8c50a6568afcac0113e61a8f6e5224a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 23 May 2016 22:14:53 -0400 Subject: [PATCH 227/267] runtime: pass gcWork to scanstack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently scanstack obtains its own gcWork from the P for the duration of the stack scan and then, if called during mark termination, disposes the gcWork. However, this means that the number of workbufs allocated will be at least the number of stacks scanned during mark termination, which may be very high (especially during a STW GC). This happens because, in steady state, each scanstack will obtain a fresh workbuf (either from the empty list or by allocating it), fill it with the scan results, and then dispose it to the full list. Nothing is consuming from the full list during this (and hence nothing is recycling them to the empty list), so the length of the full list by the time mark termination starts draining it is at least the number of stacks scanned. Fix this by pushing the gcWork acquisition up the stack to either the gcDrain that calls markroot that calls scanstack (which batches across many stack scans and is the path taken during STW GC) or to newstack (which is still a single scanstack call, but this is roughly bounded by the number of Ps). This fix reduces the workbuf allocation for the test program from issue #15319 from 213 MB (roughly 2KB * 1e5 goroutines) to 10 MB. Fixes #15319. Note that there's potentially a similar issue in write barriers during mark 2. Fixing that will be more difficult since there's no broader non-preemptible context, but it should also be less of a problem since the full list is being drained during mark 2. Some overall improvements in the go1 benchmarks, plus the usual noise. No significant change in the garbage benchmark (time/op or GC memory). name old time/op new time/op delta BinaryTree17-12 2.54s ± 1% 2.51s ± 1% -1.09% (p=0.000 n=20+19) Fannkuch11-12 2.12s ± 0% 2.17s ± 0% +2.18% (p=0.000 n=19+18) FmtFprintfEmpty-12 45.1ns ± 1% 45.2ns ± 0% ~ (p=0.078 n=19+18) FmtFprintfString-12 127ns ± 0% 128ns ± 0% +1.08% (p=0.000 n=19+16) FmtFprintfInt-12 125ns ± 0% 122ns ± 1% -2.71% (p=0.000 n=14+18) FmtFprintfIntInt-12 196ns ± 0% 190ns ± 1% -2.91% (p=0.000 n=12+20) FmtFprintfPrefixedInt-12 196ns ± 0% 194ns ± 1% -0.94% (p=0.000 n=13+18) FmtFprintfFloat-12 253ns ± 1% 251ns ± 1% -0.86% (p=0.000 n=19+20) FmtManyArgs-12 807ns ± 1% 784ns ± 1% -2.85% (p=0.000 n=20+20) GobDecode-12 7.13ms ± 1% 7.12ms ± 1% ~ (p=0.351 n=19+20) GobEncode-12 5.89ms ± 0% 5.95ms ± 0% +0.94% (p=0.000 n=19+19) Gzip-12 219ms ± 1% 221ms ± 1% +1.35% (p=0.000 n=18+20) Gunzip-12 37.5ms ± 1% 37.4ms ± 0% ~ (p=0.057 n=20+19) HTTPClientServer-12 81.4µs ± 4% 81.9µs ± 3% ~ (p=0.118 n=17+18) JSONEncode-12 15.7ms ± 1% 15.8ms ± 1% +0.73% (p=0.000 n=17+18) JSONDecode-12 57.9ms ± 1% 57.2ms ± 1% -1.34% (p=0.000 n=19+19) Mandelbrot200-12 4.12ms ± 1% 4.10ms ± 0% -0.33% (p=0.000 n=19+17) GoParse-12 3.22ms ± 2% 3.25ms ± 1% +0.72% (p=0.000 n=18+20) RegexpMatchEasy0_32-12 70.6ns ± 1% 71.1ns ± 2% +0.63% (p=0.005 n=19+20) RegexpMatchEasy0_1K-12 240ns ± 0% 239ns ± 1% -0.59% (p=0.000 n=19+20) RegexpMatchEasy1_32-12 71.3ns ± 1% 71.3ns ± 1% ~ (p=0.844 n=17+17) RegexpMatchEasy1_1K-12 384ns ± 2% 371ns ± 1% -3.45% (p=0.000 n=19+20) RegexpMatchMedium_32-12 109ns ± 1% 108ns ± 2% -0.48% (p=0.029 n=19+19) RegexpMatchMedium_1K-12 34.3µs ± 1% 34.5µs ± 2% ~ (p=0.160 n=18+20) RegexpMatchHard_32-12 1.79µs ± 9% 1.72µs ± 2% -3.83% (p=0.000 n=19+19) RegexpMatchHard_1K-12 53.3µs ± 4% 51.8µs ± 1% -2.82% (p=0.000 n=19+20) Revcomp-12 386ms ± 0% 388ms ± 0% +0.72% (p=0.000 n=17+20) Template-12 62.9ms ± 1% 62.5ms ± 1% -0.57% (p=0.010 n=18+19) TimeParse-12 325ns ± 0% 331ns ± 0% +1.84% (p=0.000 n=18+19) TimeFormat-12 338ns ± 0% 343ns ± 0% +1.34% (p=0.000 n=18+20) [Geo mean] 52.7µs 52.5µs -0.42% Change-Id: Ib2d34736c4ae2ec329605b0fbc44636038d8d018 Reviewed-on: https://go-review.googlesource.com/23391 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/mgcmark.go | 8 ++------ src/runtime/proc.go | 4 ++-- src/runtime/stack.go | 8 +++++++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index b0e7477d50d9e4..2d0cbd203c219f 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -231,7 +231,7 @@ func markroot(gcw *gcWork, i uint32) { // we scan the stacks we can and ask running // goroutines to scan themselves; and the // second blocks. - scang(gp) + scang(gp, gcw) if selfScan { casgstatus(userG, _Gwaiting, _Grunning) @@ -653,7 +653,7 @@ func gcFlushBgCredit(scanWork int64) { // //go:nowritebarrier //go:systemstack -func scanstack(gp *g) { +func scanstack(gp *g, gcw *gcWork) { if gp.gcscanvalid { return } @@ -742,7 +742,6 @@ func scanstack(gp *g) { // Scan the stack. var cache pcvalueCache - gcw := &getg().m.p.ptr().gcw n := 0 scanframe := func(frame *stkframe, unused unsafe.Pointer) bool { scanframeworker(frame, &cache, gcw) @@ -770,9 +769,6 @@ func scanstack(gp *g) { } gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0) tracebackdefers(gp, scanframe, nil) - if gcphase == _GCmarktermination { - gcw.dispose() - } gcUnlockStackBarriers(gp) if gcphase == _GCmark { // gp may have added itself to the rescan list between diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 3a37fa947beeaa..8f98cfa8a4a911 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -792,7 +792,7 @@ func casgcopystack(gp *g) uint32 { // scang blocks until gp's stack has been scanned. // It might be scanned by scang or it might be scanned by the goroutine itself. // Either way, the stack scan has completed when scang returns. -func scang(gp *g) { +func scang(gp *g, gcw *gcWork) { // Invariant; we (the caller, markroot for a specific goroutine) own gp.gcscandone. // Nothing is racing with us now, but gcscandone might be set to true left over // from an earlier round of stack scanning (we scan twice per GC). @@ -833,7 +833,7 @@ loop: // the goroutine until we're done. if castogscanstatus(gp, s, s|_Gscan) { if !gp.gcscandone { - scanstack(gp) + scanstack(gp, gcw) gp.gcscandone = true } restartg(gp) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index f68c513fd67e39..33d29f19a8cedc 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1010,7 +1010,13 @@ func newstack() { // return. } if !gp.gcscandone { - scanstack(gp) + // gcw is safe because we're on the + // system stack. + gcw := &gp.m.p.ptr().gcw + scanstack(gp, gcw) + if gcBlackenPromptly { + gcw.dispose() + } gp.gcscandone = true } gp.preemptscan = false From 10c8b2374f413ef6225555893cad5d2a530f77d5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 17:24:11 -0400 Subject: [PATCH 228/267] runtime: align C library startup calls on amd64 This makes GOEXPERIMENT=framepointer, GOOS=darwin, and buildmode=carchive coexist. Change-Id: I9f6fb2f0f06f27df683e5b51f2fa55cd21872453 Reviewed-on: https://go-review.googlesource.com/23454 Reviewed-by: Austin Clements --- src/runtime/rt0_darwin_amd64.s | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/runtime/rt0_darwin_amd64.s b/src/runtime/rt0_darwin_amd64.s index ad46fd406dc208..655e77a86bde72 100644 --- a/src/runtime/rt0_darwin_amd64.s +++ b/src/runtime/rt0_darwin_amd64.s @@ -12,7 +12,14 @@ TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8 // When linking with -shared, this symbol is called when the shared library // is loaded. -TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x48 +TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x58 + // Align stack. We don't know whether Go is adding a frame pointer here or not. + MOVQ SP, R8 + SUBQ $16, R8 + ANDQ $~15, R8 + XCHGQ SP, R8 + + MOVQ R8, 0x48(SP) MOVQ BX, 0x18(SP) MOVQ BP, 0x20(SP) MOVQ R12, 0x28(SP) @@ -51,6 +58,9 @@ restore: MOVQ 0x30(SP), R13 MOVQ 0x38(SP), R14 MOVQ 0x40(SP), R15 + + MOVQ 0x48(SP), R8 + MOVQ R8, SP RET TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0 From a5d1a72a40b59db0d2f3f5d3fbb2ed60aafb7fdf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 19 May 2016 16:27:23 -0700 Subject: [PATCH 229/267] cmd/cgo, runtime, runtime/cgo: TSAN support for malloc Acquire and release the TSAN synchronization point when calling malloc, just as we do when calling any other C function. If we don't do this, TSAN will report false positive errors about races calling malloc and free. We used to have a special code path for malloc and free, going through the runtime functions cmalloc and cfree. The special code path for cfree was no longer used even before this CL. This CL stops using the special code path for malloc, because there is no place along that path where we could conditionally insert the TSAN synchronization. This CL removes the support for the special code path for both functions. Instead, cgo now automatically generates the malloc function as though it were referenced as C.malloc. We need to automatically generate it even if C.malloc is not called, even if malloc and size_t are not declared, to support cgo-provided functions like C.CString. Change-Id: I829854ec0787a80f33fa0a8a0dc2ee1d617830e2 Reviewed-on: https://go-review.googlesource.com/23260 Reviewed-by: Dmitry Vyukov Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- misc/cgo/testsanitizers/test.bash | 10 +++++ misc/cgo/testsanitizers/tsan4.go | 34 +++++++++++++++ src/cmd/cgo/out.go | 69 +++++++++++++++++++++++++++---- src/runtime/cgo.go | 4 -- src/runtime/cgo/callbacks.go | 12 ------ src/runtime/cgo/gcc_util.c | 25 ----------- src/runtime/cgocall.go | 19 --------- src/runtime/proc.go | 6 --- 8 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 misc/cgo/testsanitizers/tsan4.go diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash index 8718815d3e19c2..c30df3b6c2a5ec 100755 --- a/misc/cgo/testsanitizers/test.bash +++ b/misc/cgo/testsanitizers/test.bash @@ -144,6 +144,16 @@ if test "$tsan" = "yes"; then status=1 fi + if ! go run tsan4.go 2>$err; then + cat $err + echo "FAIL: tsan4" + status=1 + elif grep -i warning $err >/dev/null 2>&1; then + cat $err + echo "FAIL: tsan4" + status=1 + fi + rm -f $err fi diff --git a/misc/cgo/testsanitizers/tsan4.go b/misc/cgo/testsanitizers/tsan4.go new file mode 100644 index 00000000000000..f0c76d84116a60 --- /dev/null +++ b/misc/cgo/testsanitizers/tsan4.go @@ -0,0 +1,34 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Check that calls to C.malloc/C.free do not trigger TSAN false +// positive reports. + +// #cgo CFLAGS: -fsanitize=thread +// #cgo LDFLAGS: -fsanitize=thread +// #include +import "C" + +import ( + "runtime" + "sync" +) + +func main() { + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + p := C.malloc(C.size_t(i * 10)) + runtime.Gosched() + C.free(p) + } + }() + } + wg.Wait() +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 256b059e57211b..5d6930d3ea402c 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -175,10 +175,11 @@ func (p *Package) writeDefs() { } fmt.Fprintf(fgo2, "\n") + callsMalloc := false for _, key := range nameKeys(p.Name) { n := p.Name[key] if n.FuncType != nil { - p.writeDefsFunc(fgo2, n) + p.writeDefsFunc(fgo2, n, &callsMalloc) } } @@ -189,6 +190,12 @@ func (p *Package) writeDefs() { } else { p.writeExports(fgo2, fm, fgcc, fgcch) } + + if callsMalloc && !*gccgo { + fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1)) + fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1)) + } + if err := fgcc.Close(); err != nil { fatalf("%s", err) } @@ -352,7 +359,7 @@ func (p *Package) structType(n *Name) (string, int64) { return buf.String(), off } -func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) { +func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { name := n.Go gtype := n.FuncType.Go void := gtype.Results == nil || len(gtype.Results.List) == 0 @@ -441,6 +448,9 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) { if inProlog { fmt.Fprint(fgo2, builtinDefs[name]) + if strings.Contains(builtinDefs[name], "_cgo_cmalloc") { + *callsMalloc = true + } return } @@ -712,11 +722,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { p.writeExportHeader(fgcch) fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "#include \n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n") fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n") fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n") fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n") + fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);") fmt.Fprintf(fgcc, "%s\n", tsanProlog) for _, exp := range p.ExpFunc { @@ -1352,9 +1364,6 @@ const goProlog = ` //go:linkname _cgo_runtime_cgocall runtime.cgocall func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32 -//go:linkname _cgo_runtime_cmalloc runtime.cmalloc -func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer - //go:linkname _cgo_runtime_cgocallback runtime.cgocallback func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr) @@ -1400,7 +1409,7 @@ func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte { const cStringDef = ` func _Cfunc_CString(s string) *_Ctype_char { - p := _cgo_runtime_cmalloc(uintptr(len(s)+1)) + p := _cgo_cmalloc(uint64(len(s)+1)) pp := (*[1<<30]byte)(p) copy(pp[:], s) pp[len(s)] = 0 @@ -1410,7 +1419,7 @@ func _Cfunc_CString(s string) *_Ctype_char { const cBytesDef = ` func _Cfunc_CBytes(b []byte) unsafe.Pointer { - p := _cgo_runtime_cmalloc(uintptr(len(b))) + p := _cgo_cmalloc(uint64(len(b))) pp := (*[1<<30]byte)(p) copy(pp[:], b) return p @@ -1419,7 +1428,7 @@ func _Cfunc_CBytes(b []byte) unsafe.Pointer { const cMallocDef = ` func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer { - return _cgo_runtime_cmalloc(uintptr(n)) + return _cgo_cmalloc(uint64(n)) } ` @@ -1432,6 +1441,50 @@ var builtinDefs = map[string]string{ "_CMalloc": cMallocDef, } +// Definitions for C.malloc in Go and in C. We define it ourselves +// since we call it from functions we define, such as C.CString. +// Also, we have historically ensured that C.malloc does not return +// nil even for an allocation of 0. + +const cMallocDefGo = ` +//go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc +//go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc +var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte +var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc) + +//go:cgo_unsafe_args +func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) { + _cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0))) + return +} +` + +// cMallocDefC defines the C version of C.malloc for the gc compiler. +// It is defined here because C.CString and friends need a definition. +// We define it by hand, rather than simply inventing a reference to +// C.malloc, because may not have been included. +// This is approximately what writeOutputFunc would generate, but +// skips the cgo_topofstack code (which is only needed if the C code +// calls back into Go). This also avoids returning nil for an +// allocation of 0 bytes. +const cMallocDefC = ` +CGO_NO_SANITIZE_THREAD +void _cgoPREFIX_Cfunc__Cmalloc(void *v) { + struct { + unsigned long long p0; + void *r1; + } PACKED *a = v; + void *ret; + _cgo_tsan_acquire(); + ret = malloc(a->p0); + if (ret == 0 && a->p0 == 0) { + ret = malloc(1); + } + a->r1 = ret; + _cgo_tsan_release(); +} +` + func (p *Package) cPrologGccgo() string { return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1), "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1) diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go index 4fb4a613e044d4..9cf7b58a2f7a2e 100644 --- a/src/runtime/cgo.go +++ b/src/runtime/cgo.go @@ -11,8 +11,6 @@ import "unsafe" // Filled in by runtime/cgo when linked into binary. //go:linkname _cgo_init _cgo_init -//go:linkname _cgo_malloc _cgo_malloc -//go:linkname _cgo_free _cgo_free //go:linkname _cgo_thread_start _cgo_thread_start //go:linkname _cgo_sys_thread_create _cgo_sys_thread_create //go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done @@ -21,8 +19,6 @@ import "unsafe" var ( _cgo_init unsafe.Pointer - _cgo_malloc unsafe.Pointer - _cgo_free unsafe.Pointer _cgo_thread_start unsafe.Pointer _cgo_sys_thread_create unsafe.Pointer _cgo_notify_runtime_init_done unsafe.Pointer diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go index d0f63fb4ff9d74..9bde5a933fcd15 100644 --- a/src/runtime/cgo/callbacks.go +++ b/src/runtime/cgo/callbacks.go @@ -52,18 +52,6 @@ func _cgo_panic(a unsafe.Pointer, n int32) { var x_cgo_init byte var _cgo_init = &x_cgo_init -//go:cgo_import_static x_cgo_malloc -//go:linkname x_cgo_malloc x_cgo_malloc -//go:linkname _cgo_malloc _cgo_malloc -var x_cgo_malloc byte -var _cgo_malloc = &x_cgo_malloc - -//go:cgo_import_static x_cgo_free -//go:linkname x_cgo_free x_cgo_free -//go:linkname _cgo_free _cgo_free -var x_cgo_free byte -var _cgo_free = &x_cgo_free - //go:cgo_import_static x_cgo_thread_start //go:linkname x_cgo_thread_start x_cgo_thread_start //go:linkname _cgo_thread_start _cgo_thread_start diff --git a/src/runtime/cgo/gcc_util.c b/src/runtime/cgo/gcc_util.c index e20d206be6d799..4111fe11951df8 100644 --- a/src/runtime/cgo/gcc_util.c +++ b/src/runtime/cgo/gcc_util.c @@ -4,31 +4,6 @@ #include "libcgo.h" -/* Stub for calling malloc from Go */ -void -x_cgo_malloc(void *p) -{ - struct a { - long long n; - void *ret; - } *a = p; - - a->ret = malloc(a->n); - if(a->ret == NULL && a->n == 0) - a->ret = malloc(1); -} - -/* Stub for calling free from Go */ -void -x_cgo_free(void *p) -{ - struct a { - void *arg; - } *a = p; - - free(a->arg); -} - /* Stub for creating a new thread */ void x_cgo_thread_start(ThreadStart *arg) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 1e0d4c7f19504a..0f8386b10f54d5 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -145,25 +145,6 @@ func endcgo(mp *m) { unlockOSThread() // invalidates mp } -// Helper functions for cgo code. - -func cmalloc(n uintptr) unsafe.Pointer { - var args struct { - n uint64 - ret unsafe.Pointer - } - args.n = uint64(n) - cgocall(_cgo_malloc, unsafe.Pointer(&args)) - if args.ret == nil { - throw("C malloc failed") - } - return args.ret -} - -func cfree(p unsafe.Pointer) { - cgocall(_cgo_free, p) -} - // Call from C back to Go. //go:nosplit func cgocallbackg(ctxt uintptr) { diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 8f98cfa8a4a911..ee895471046e62 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -155,12 +155,6 @@ func main() { if _cgo_thread_start == nil { throw("_cgo_thread_start missing") } - if _cgo_malloc == nil { - throw("_cgo_malloc missing") - } - if _cgo_free == nil { - throw("_cgo_free missing") - } if GOOS != "windows" { if _cgo_setenv == nil { throw("_cgo_setenv missing") From b9ec0024fbc18dd94eff7240afd82fac6b4d8fdc Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Thu, 12 May 2016 16:26:27 -0400 Subject: [PATCH 230/267] net/http: add missing HTTP status codes This commit adds missing status codes: * 102 - Processing * 207 - Multi-Status * 208 - Already Reported * 226 - IM Used * 308 - Permanent Redirect * 422 - Unprocessable Entity * 423 - Locked * 424 - Failed Dependency * 426 - Upgrade Required * 506 - Variant Also Negotiates * 507 - Insufficient Storage * 508 - Loop Detected * 510 - Not Extended * 511 - Network Authentication Required Change-Id: Ife0e5b064f4b1e3542d2fd41abc9e7b1e410b644 Reviewed-on: https://go-review.googlesource.com/23090 Reviewed-by: Andrew Gerrand Run-TryBot: Andrew Gerrand TryBot-Result: Gobot Gobot --- src/net/http/status.go | 122 +++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 47 deletions(-) diff --git a/src/net/http/status.go b/src/net/http/status.go index f3dacab6a92043..98645b7d746637 100644 --- a/src/net/http/status.go +++ b/src/net/http/status.go @@ -4,63 +4,79 @@ package http -// HTTP status codes, defined in RFC 2616. +// HTTP status codes as registered with IANA. +// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml const ( - StatusContinue = 100 - StatusSwitchingProtocols = 101 + StatusContinue = 100 // RFC 7231, 6.2.1 + StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2 + StatusProcessing = 102 // RFC 2518, 10.1 - StatusOK = 200 - StatusCreated = 201 - StatusAccepted = 202 - StatusNonAuthoritativeInfo = 203 - StatusNoContent = 204 - StatusResetContent = 205 - StatusPartialContent = 206 + StatusOK = 200 // RFC 7231, 6.3.1 + StatusCreated = 201 // RFC 7231, 6.3.2 + StatusAccepted = 202 // RFC 7231, 6.3.3 + StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4 + StatusNoContent = 204 // RFC 7231, 6.3.5 + StatusResetContent = 205 // RFC 7231, 6.3.6 + StatusPartialContent = 206 // RFC 7233, 4.1 + StatusMultiStatus = 207 // RFC 4918, 11.1 + StatusAlreadyReported = 208 // RFC 5842, 7.1 + StatusIMUsed = 226 // RFC 3229, 10.4.1 - StatusMultipleChoices = 300 - StatusMovedPermanently = 301 - StatusFound = 302 - StatusSeeOther = 303 - StatusNotModified = 304 - StatusUseProxy = 305 - StatusTemporaryRedirect = 307 + StatusMultipleChoices = 300 // RFC 7231, 6.4.1 + StatusMovedPermanently = 301 // RFC 7231, 6.4.2 + StatusFound = 302 // RFC 7231, 6.4.3 + StatusSeeOther = 303 // RFC 7231, 6.4.4 + StatusNotModified = 304 // RFC 7232, 4.1 + StatusUseProxy = 305 // RFC 7231, 6.4.5 + _ = 306 // RFC 7231, 6.4.6 (Unused) + StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7 + StatusPermanentRedirect = 308 // RFC 7538, 3 - StatusBadRequest = 400 - StatusUnauthorized = 401 - StatusPaymentRequired = 402 - StatusForbidden = 403 - StatusNotFound = 404 - StatusMethodNotAllowed = 405 - StatusNotAcceptable = 406 - StatusProxyAuthRequired = 407 - StatusRequestTimeout = 408 - StatusConflict = 409 - StatusGone = 410 - StatusLengthRequired = 411 - StatusPreconditionFailed = 412 - StatusRequestEntityTooLarge = 413 - StatusRequestURITooLong = 414 - StatusUnsupportedMediaType = 415 - StatusRequestedRangeNotSatisfiable = 416 - StatusExpectationFailed = 417 - StatusTeapot = 418 - StatusPreconditionRequired = 428 - StatusTooManyRequests = 429 - StatusRequestHeaderFieldsTooLarge = 431 - StatusUnavailableForLegalReasons = 451 + StatusBadRequest = 400 // RFC 7231, 6.5.1 + StatusUnauthorized = 401 // RFC 7235, 3.1 + StatusPaymentRequired = 402 // RFC 7231, 6.5.2 + StatusForbidden = 403 // RFC 7231, 6.5.3 + StatusNotFound = 404 // RFC 7231, 6.5.4 + StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5 + StatusNotAcceptable = 406 // RFC 7231, 6.5.6 + StatusProxyAuthRequired = 407 // RFC 7235, 3.2 + StatusRequestTimeout = 408 // RFC 7231, 6.5.7 + StatusConflict = 409 // RFC 7231, 6.5.8 + StatusGone = 410 // RFC 7231, 6.5.9 + StatusLengthRequired = 411 // RFC 7231, 6.5.10 + StatusPreconditionFailed = 412 // RFC 7232, 4.2 + StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11 + StatusRequestURITooLong = 414 // RFC 7231, 6.5.12 + StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13 + StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4 + StatusExpectationFailed = 417 // RFC 7231, 6.5.14 + StatusTeapot = 418 // RFC 7168, 2.3.3 + StatusUnprocessableEntity = 422 // RFC 4918, 11.2 + StatusLocked = 423 // RFC 4918, 11.3 + StatusFailedDependency = 424 // RFC 4918, 11.4 + StatusUpgradeRequired = 426 // RFC 7231, 6.5.15 + StatusPreconditionRequired = 428 // RFC 6585, 3 + StatusTooManyRequests = 429 // RFC 6585, 4 + StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5 + StatusUnavailableForLegalReasons = 451 // RFC 7725, 3 - StatusInternalServerError = 500 - StatusNotImplemented = 501 - StatusBadGateway = 502 - StatusServiceUnavailable = 503 - StatusGatewayTimeout = 504 - StatusHTTPVersionNotSupported = 505 - StatusNetworkAuthenticationRequired = 511 + StatusInternalServerError = 500 // RFC 7231, 6.6.1 + StatusNotImplemented = 501 // RFC 7231, 6.6.2 + StatusBadGateway = 502 // RFC 7231, 6.6.3 + StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 + StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 + StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 + StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 + StatusInsufficientStorage = 507 // RFC 4918, 11.5 + StatusLoopDetected = 508 // RFC 5842, 7.2 + StatusNotExtended = 510 // RFC 2774, 7 + StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 ) var statusText = map[int]string{ StatusContinue: "Continue", StatusSwitchingProtocols: "Switching Protocols", + StatusProcessing: "Processing", StatusOK: "OK", StatusCreated: "Created", @@ -69,6 +85,9 @@ var statusText = map[int]string{ StatusNoContent: "No Content", StatusResetContent: "Reset Content", StatusPartialContent: "Partial Content", + StatusMultiStatus: "Multi-Status", + StatusAlreadyReported: "Already Reported", + StatusIMUsed: "IM Used", StatusMultipleChoices: "Multiple Choices", StatusMovedPermanently: "Moved Permanently", @@ -77,6 +96,7 @@ var statusText = map[int]string{ StatusNotModified: "Not Modified", StatusUseProxy: "Use Proxy", StatusTemporaryRedirect: "Temporary Redirect", + StatusPermanentRedirect: "Permanent Redirect", StatusBadRequest: "Bad Request", StatusUnauthorized: "Unauthorized", @@ -97,6 +117,10 @@ var statusText = map[int]string{ StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable", StatusExpectationFailed: "Expectation Failed", StatusTeapot: "I'm a teapot", + StatusUnprocessableEntity: "Unprocessable Entity", + StatusLocked: "Locked", + StatusFailedDependency: "Failed Dependency", + StatusUpgradeRequired: "Upgrade Required", StatusPreconditionRequired: "Precondition Required", StatusTooManyRequests: "Too Many Requests", StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large", @@ -108,6 +132,10 @@ var statusText = map[int]string{ StatusServiceUnavailable: "Service Unavailable", StatusGatewayTimeout: "Gateway Timeout", StatusHTTPVersionNotSupported: "HTTP Version Not Supported", + StatusVariantAlsoNegotiates: "Variant Also Negotiates", + StatusInsufficientStorage: "Insufficient Storage", + StatusLoopDetected: "Loop Detected", + StatusNotExtended: "Not Extended", StatusNetworkAuthenticationRequired: "Network Authentication Required", } From 30282b091d6c80f4aa37d7c457fa288c3a181573 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 25 May 2016 16:38:02 -0700 Subject: [PATCH 231/267] cmd/compile: correctly import labels, gotos, and fallthroughs The importer had several bugs with respect to labels and gotos: - it didn't create a new ONAME node for label names (label dcl, goto, continue, and break) - it overwrote the symbol for gotos with the dclstack - it didn't set the dclstack for labels In the process changed export format slightly to always assume a label name for labels and gotos, and never assume a label for fallthroughs. For fallthroughs and switch cases, now also set Xoffset like in the parser. (Not setting it, i.e., using 0 was ok since this is only used for verifying correct use of fallthroughs, which was checked already. But it's an extra level of verification of the import.) Fixes #15838. Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483 Reviewed-on: https://go-review.googlesource.com/23445 Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/bexport.go | 11 +++-- src/cmd/compile/internal/gc/bimport.go | 17 +++++-- test/fixedbugs/issue15838.dir/a.go | 61 ++++++++++++++++++++++++++ test/fixedbugs/issue15838.dir/b.go | 9 ++++ test/fixedbugs/issue15838.go | 12 +++++ 5 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 test/fixedbugs/issue15838.dir/a.go create mode 100644 test/fixedbugs/issue15838.dir/b.go create mode 100644 test/fixedbugs/issue15838.go diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 1997068d1af4ef..80b8e4f9450df3 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1488,19 +1488,18 @@ func (p *exporter) stmt(n *Node) { p.stmtList(n.List) p.stmtList(n.Nbody) - case OFALL: - op = OXFALL - fallthrough + case OFALL, OXFALL: + p.op(OXFALL) - case OBREAK, OCONTINUE, OGOTO, OXFALL: + case OBREAK, OCONTINUE: p.op(op) p.exprsOrNil(n.Left, nil) case OEMPTY: // nothing to emit - case OLABEL: - p.op(OLABEL) + case OGOTO, OLABEL: + p.op(op) p.expr(n.Left) default: diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index b9e69c24bb9a87..36aa0e8b9ceaf3 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -1038,6 +1038,7 @@ func (p *importer) node() *Node { case OXCASE: markdcl() n := Nod(OXCASE, nil, nil) + n.Xoffset = int64(block) n.List.Set(p.exprList()) // TODO(gri) eventually we must declare variables for type switch // statements (type switch statements are not yet exported) @@ -1048,16 +1049,24 @@ func (p *importer) node() *Node { // case OFALL: // unreachable - mapped to OXFALL case below by exporter - case OBREAK, OCONTINUE, OGOTO, OXFALL: + case OXFALL: + n := Nod(OXFALL, nil, nil) + n.Xoffset = int64(block) + return n + + case OBREAK, OCONTINUE: left, _ := p.exprsOrNil() + if left != nil { + left = newname(left.Sym) + } return Nod(op, left, nil) // case OEMPTY: // unreachable - not emitted by exporter - case OLABEL: - n := Nod(OLABEL, p.expr(), nil) - n.Left.Sym = dclstack // context, for goto restrictions + case OGOTO, OLABEL: + n := Nod(op, newname(p.expr().Sym), nil) + n.Sym = dclstack // context, for goto restrictions return n case OEND: diff --git a/test/fixedbugs/issue15838.dir/a.go b/test/fixedbugs/issue15838.dir/a.go new file mode 100644 index 00000000000000..15b7f1dcfa8230 --- /dev/null +++ b/test/fixedbugs/issue15838.dir/a.go @@ -0,0 +1,61 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F1() { +L: + goto L +} + +func F2() { +L: + for { + break L + } +} + +func F3() { +L: + for { + continue L + } +} + +func F4() { + switch { + case true: + fallthrough + default: + } +} + +type T struct{} + +func (T) M1() { +L: + goto L +} + +func (T) M2() { +L: + for { + break L + } +} + +func (T) M3() { +L: + for { + continue L + } +} + +func (T) M4() { + switch { + case true: + fallthrough + default: + } +} diff --git a/test/fixedbugs/issue15838.dir/b.go b/test/fixedbugs/issue15838.dir/b.go new file mode 100644 index 00000000000000..9fd6efc33c9b89 --- /dev/null +++ b/test/fixedbugs/issue15838.dir/b.go @@ -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. + +package b + +import "./a" + +type T struct{ a.T } diff --git a/test/fixedbugs/issue15838.go b/test/fixedbugs/issue15838.go new file mode 100644 index 00000000000000..fb1c64d1ac19dc --- /dev/null +++ b/test/fixedbugs/issue15838.go @@ -0,0 +1,12 @@ +// compiledir + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test cases for issue #15838, and related failures. +// Make sure the importer correctly sets up nodes for +// label decls, goto, continue, break, and fallthrough +// statements. + +package ignored From 8a1dc3244725c2afd170025fc616df840b464a99 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 14:54:21 -0400 Subject: [PATCH 232/267] runtime: add library startup support for ppc64le I have been running this patch inside Google against Go 1.6 for the last month. The new tests will probably break the builders but let's see exactly how they break. Change-Id: Ia65cf7d3faecffeeb4b06e9b80875c0e57d86d9e Reviewed-on: https://go-review.googlesource.com/23452 Reviewed-by: Ian Lance Taylor --- src/cmd/dist/test.go | 6 +- src/runtime/rt0_linux_ppc64le.s | 129 ++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 1a1f7d961bea77..366b3af9ae7a57 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -680,7 +680,8 @@ func (t *tester) supportedBuildmode(mode string) bool { } switch pair { case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", - "linux-amd64", "linux-386", "windows-amd64", "windows-386": + "linux-amd64", "linux-386", "windows-amd64", "windows-386", + "linux-ppc64le": return true } return false @@ -688,7 +689,8 @@ func (t *tester) supportedBuildmode(mode string) bool { switch pair { case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "darwin-amd64", "darwin-386", - "android-arm", "android-arm64", "android-386": + "android-arm", "android-arm64", "android-386", + "linux-ppc64le": return true } return false diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s index ac7b9225a43bef..2c5541357f2af7 100644 --- a/src/runtime/rt0_linux_ppc64le.s +++ b/src/runtime/rt0_linux_ppc64le.s @@ -4,6 +4,135 @@ TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0 BR _main<>(SB) +TEXT _rt0_ppc64le_linux_lib(SB),NOSPLIT,$-8 + // Start with standard C stack frame layout and linkage. + MOVD LR, R0 + MOVD R0, 16(R1) // Save LR in caller's frame. + MOVD R2, 24(R1) // Save TOC in caller's frame. + MOVDU R1, -320(R1) // Allocate frame. + + // Preserve callee-save registers. + MOVD R14, 24(R1) + MOVD R15, 32(R1) + MOVD R16, 40(R1) + MOVD R17, 48(R1) + MOVD R18, 56(R1) + MOVD R19, 64(R1) + MOVD R20, 72(R1) + MOVD R21, 80(R1) + MOVD R22, 88(R1) + MOVD R23, 96(R1) + MOVD R24, 104(R1) + MOVD R25, 112(R1) + MOVD R26, 120(R1) + MOVD R27, 128(R1) + MOVD R28, 136(R1) + MOVD R29, 144(R1) + MOVD g, 152(R1) // R30 + MOVD R31, 160(R1) + FMOVD F14, 168(R1) + FMOVD F15, 176(R1) + FMOVD F16, 184(R1) + FMOVD F17, 192(R1) + FMOVD F18, 200(R1) + FMOVD F19, 208(R1) + FMOVD F20, 216(R1) + FMOVD F21, 224(R1) + FMOVD F22, 232(R1) + FMOVD F23, 240(R1) + FMOVD F24, 248(R1) + FMOVD F25, 256(R1) + FMOVD F26, 264(R1) + FMOVD F27, 272(R1) + FMOVD F28, 280(R1) + FMOVD F29, 288(R1) + FMOVD F30, 296(R1) + FMOVD F31, 304(R1) + + MOVD R3, _rt0_ppc64le_linux_lib_argc<>(SB) + MOVD R4, _rt0_ppc64le_linux_lib_argv<>(SB) + + // Synchronous initialization. + MOVD $runtime·libpreinit(SB), R12 + MOVD R12, CTR + BL (CTR) + + // Create a new thread to do the runtime initialization and return. + MOVD _cgo_sys_thread_create(SB), R12 + CMP $0, R12 + BEQ nocgo + MOVD $_rt0_ppc64le_linux_lib_go(SB), R3 + MOVD $0, R4 + MOVD R12, CTR + BL (CTR) + BR done + +nocgo: + MOVD $0x800000, R12 // stacksize = 8192KB + MOVD R12, 8(R1) + MOVD $_rt0_ppc64le_linux_lib_go(SB), R12 + MOVD R12, 16(R1) + MOVD $runtime·newosproc0(SB),R12 + MOVD R12, CTR + BL (CTR) + +done: + // Restore saved registers. + MOVD 24(R1), R14 + MOVD 32(R1), R15 + MOVD 40(R1), R16 + MOVD 48(R1), R17 + MOVD 56(R1), R18 + MOVD 64(R1), R19 + MOVD 72(R1), R20 + MOVD 80(R1), R21 + MOVD 88(R1), R22 + MOVD 96(R1), R23 + MOVD 104(R1), R24 + MOVD 112(R1), R25 + MOVD 120(R1), R26 + MOVD 128(R1), R27 + MOVD 136(R1), R28 + MOVD 144(R1), R29 + MOVD 152(R1), g // R30 + MOVD 160(R1), R31 + FMOVD 168(R1), F14 + FMOVD 176(R1), F15 + FMOVD 184(R1), F16 + FMOVD 192(R1), F17 + FMOVD 200(R1), F18 + FMOVD 208(R1), F19 + FMOVD 216(R1), F20 + FMOVD 224(R1), F21 + FMOVD 232(R1), F22 + FMOVD 240(R1), F23 + FMOVD 248(R1), F24 + FMOVD 256(R1), F25 + FMOVD 264(R1), F26 + FMOVD 272(R1), F27 + FMOVD 280(R1), F28 + FMOVD 288(R1), F29 + FMOVD 296(R1), F30 + FMOVD 304(R1), F31 + + ADD $320, R1 + MOVD 24(R1), R2 + MOVD 16(R1), R0 + MOVD R0, LR + RET + +TEXT _rt0_ppc64le_linux_lib_go(SB),NOSPLIT,$0 + MOVD _rt0_ppc64le_linux_lib_argc<>(SB), R3 + MOVD _rt0_ppc64le_linux_lib_argv<>(SB), R4 + MOVD $runtime·rt0_go(SB), R12 + MOVD R12, CTR + BR (CTR) + +DATA _rt0_ppc64le_linux_lib_argc<>(SB)/8, $0 +GLOBL _rt0_ppc64le_linux_lib_argc<>(SB),NOPTR, $8 +DATA _rt0_ppc64le_linux_lib_argv<>(SB)/8, $0 +GLOBL _rt0_ppc64le_linux_lib_argv<>(SB),NOPTR, $8 + TEXT _main<>(SB),NOSPLIT,$-8 // In a statically linked binary, the stack contains argc, // argv as argc string pointers followed by a NULL, envv as a From 805eaeef33a52778ba6ee624389c2cbfe6896f6f Mon Sep 17 00:00:00 2001 From: Ilya Tocar Date: Tue, 17 May 2016 20:55:55 +0300 Subject: [PATCH 233/267] crypto/sha1: fix AVX2 variant on AMD64 AVX2 variant reads next blocks while calculating current block. Avoid reading past the end of data, by switching back to original, for last blocks. Fixes #15617. Change-Id: I04fa2d83f1b47995117c77b4a3d403a7dff594d4 Reviewed-on: https://go-review.googlesource.com/23138 Reviewed-by: Keith Randall Run-TryBot: Ilya Tocar TryBot-Result: Gobot Gobot --- src/crypto/sha1/issue15617_test.go | 28 ++++++++++++++++++++++++++++ src/crypto/sha1/sha1_test.go | 16 +++++++++------- src/crypto/sha1/sha1block_amd64.go | 17 +++++++++++++---- 3 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/crypto/sha1/issue15617_test.go diff --git a/src/crypto/sha1/issue15617_test.go b/src/crypto/sha1/issue15617_test.go new file mode 100644 index 00000000000000..98038e58077c2f --- /dev/null +++ b/src/crypto/sha1/issue15617_test.go @@ -0,0 +1,28 @@ +// +build amd64 +// +build linux darwin + +// 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 sha1_test + +import ( + "crypto/sha1" + "syscall" + "testing" +) + +func TestOutOfBoundsRead(t *testing.T) { + const pageSize = 4 << 10 + data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + panic(err) + } + if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil { + panic(err) + } + for i := 0; i < pageSize; i++ { + sha1.Sum(data[pageSize-i : pageSize]) + } +} diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go index daab2aeaefb977..214afc51e1fa64 100644 --- a/src/crypto/sha1/sha1_test.go +++ b/src/crypto/sha1/sha1_test.go @@ -94,13 +94,15 @@ func TestBlockSize(t *testing.T) { // Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match. func TestBlockGeneric(t *testing.T) { - gen, asm := New().(*digest), New().(*digest) - buf := make([]byte, BlockSize*20) // arbitrary factor - rand.Read(buf) - blockGeneric(gen, buf) - block(asm, buf) - if *gen != *asm { - t.Error("block and blockGeneric resulted in different states") + for i := 1; i < 30; i++ { // arbitrary factor + gen, asm := New().(*digest), New().(*digest) + buf := make([]byte, BlockSize*i) + rand.Read(buf) + blockGeneric(gen, buf) + block(asm, buf) + if *gen != *asm { + t.Errorf("For %#v block and blockGeneric resulted in different states", buf) + } } } diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go index a36f334b115d5b..fd85a4262be21a 100644 --- a/src/crypto/sha1/sha1block_amd64.go +++ b/src/crypto/sha1/sha1block_amd64.go @@ -12,13 +12,22 @@ func blockAVX2(dig *digest, p []byte) func blockAMD64(dig *digest, p []byte) func checkAVX2() bool -// TODO(TocarIP): fix AVX2 crash (golang.org/issue/15617) and -// then re-enable this: -var hasAVX2 = false // checkAVX2() +var hasAVX2 = checkAVX2() func block(dig *digest, p []byte) { if hasAVX2 && len(p) >= 256 { - blockAVX2(dig, p) + // blockAVX2 calculates sha1 for 2 block per iteration + // it also interleaves precalculation for next block. + // So it may read up-to 192 bytes past end of p + // We may add checks inside blockAVX2, but this will + // just turn it into a copy of blockAMD64, + // so call it directly, instead. + safeLen := len(p) - 128 + if safeLen%128 != 0 { + safeLen -= 64 + } + blockAVX2(dig, p[:safeLen]) + blockAMD64(dig, p[safeLen:]) } else { blockAMD64(dig, p) } From d9557523c2febc29ad3ecab8b1a4358abd709b30 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 20:01:25 -0400 Subject: [PATCH 234/267] runtime: make framepointer mode safe for Windows A few other architectures have already defined a NOFRAME flag. Use it to disable frame pointer code on a few very low-level functions that must behave like Windows code. Makes the failing os/signal test pass on a Windows gomote. Change-Id: I982365f2c59a0aa302b4428c970846c61027cf3e Reviewed-on: https://go-review.googlesource.com/23456 Reviewed-by: Austin Clements --- src/cmd/internal/obj/x86/obj6.go | 3 +-- src/runtime/sys_windows_amd64.s | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index df774437ac51dc..0f1f28d36d6d94 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -610,12 +610,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) { } var bpsize int - if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 { + if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 0 { // Make room for to save a base pointer. If autoffset == 0, // this might do something special like a tail jump to // another function, so in that case we omit this. bpsize = ctxt.Arch.PtrSize - autoffset += int32(bpsize) p.To.Offset += int64(bpsize) } else { diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index d550a818ce85f1..9c197379fb8f42 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -11,7 +11,7 @@ #define maxargs 16 // void runtime·asmstdcall(void *c); -TEXT runtime·asmstdcall(SB),NOSPLIT,$0 +TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 // asmcgocall will put first argument into CX. PUSHQ CX // save for later MOVQ libcall_fn(CX), AX @@ -62,7 +62,7 @@ loadregs: RET -TEXT runtime·badsignal2(SB),NOSPLIT,$48 +TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$48 // stderr MOVQ $-12, CX // stderr MOVQ CX, 0(SP) @@ -102,7 +102,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // exception record and context pointers. // Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. -TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 +TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0-0 // CX: PEXCEPTION_POINTERS ExceptionInfo // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved @@ -190,32 +190,32 @@ done: RET -TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 +TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 MOVQ $runtime·exceptionhandler(SB), AX JMP runtime·sigtramp(SB) -TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 +TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 MOVQ $runtime·firstcontinuehandler(SB), AX JMP runtime·sigtramp(SB) -TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 +TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 MOVQ $runtime·lastcontinuehandler(SB), AX JMP runtime·sigtramp(SB) -TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 +TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$8 MOVQ CX, 16(SP) // spill MOVQ $runtime·ctrlhandler1(SB), CX MOVQ CX, 0(SP) CALL runtime·externalthreadhandler(SB) RET -TEXT runtime·profileloop(SB),NOSPLIT,$8 +TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$8 MOVQ $runtime·profileloop1(SB), CX MOVQ CX, 0(SP) CALL runtime·externalthreadhandler(SB) RET -TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 +TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0 PUSHQ BP MOVQ SP, BP PUSHQ BX @@ -228,7 +228,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 SUBQ $m__size, SP // space for M MOVQ SP, 0(SP) MOVQ $m__size, 8(SP) - CALL runtime·memclr(SB) // smashes AX,BX,CX + CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP LEAQ m_tls(SP), CX MOVQ CX, 0x28(GS) @@ -239,7 +239,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 MOVQ SP, 0(SP) MOVQ $g__size, 8(SP) - CALL runtime·memclr(SB) // smashes AX,BX,CX + CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP LEAQ g__size(SP), BX MOVQ BX, g_m(SP) @@ -430,7 +430,7 @@ ret: // Runs on OS stack. duration (in 100ns units) is in BX. // The function leaves room for 4 syscall parameters // (as per windows amd64 calling convention). -TEXT runtime·usleep2(SB),NOSPLIT,$48 +TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48 MOVQ SP, AX ANDQ $~15, SP // alignment as per Windows requirement MOVQ AX, 40(SP) @@ -446,7 +446,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$48 RET // Runs on OS stack. -TEXT runtime·switchtothread(SB),NOSPLIT,$0 +TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 MOVQ SP, AX ANDQ $~15, SP // alignment as per Windows requirement SUBQ $(48), SP // room for SP and 4 args as per Windows requirement From adff422779709c83db91700fdcc0a0bd5dee6a21 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 25 May 2016 22:59:19 -0400 Subject: [PATCH 235/267] cmd/link/internal/ld: fix DWARF offsets with GOEXPERIMENT=framepointer The offsets computed by the DWARF expressions for local variables currently don't account for the extra stack slot used by the frame pointer when GOEXPERIMENT=framepointer is enabled. Fix this by adding the extra stack slot to the offset. This fixes TestGdbPython with GOEXPERIMENT=framepointer. Updates #15840. Change-Id: I1b2ebb2750cd22266f4a89ec8d9e8bfa05fabd19 Reviewed-on: https://go-review.googlesource.com/23458 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/dwarf.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index bf1a7e74c1403f..ca86e72d8329cc 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1558,6 +1558,12 @@ func writelines(prev *LSym) *LSym { if !haslinkregister() { offs -= int64(SysArch.PtrSize) } + if obj.Framepointer_enabled != 0 { + // The frame pointer is saved + // between the CFA and the + // autos. + offs -= int64(SysArch.PtrSize) + } case obj.A_PARAM: dt = DW_ABRV_PARAM From b92f4238790c590168e7dae03165d75deb89fe41 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 25 May 2016 20:56:56 -0400 Subject: [PATCH 236/267] runtime: unwind BP in jmpdefer to match SP unwind The irregular calling convention for defers currently incorrectly manages the BP if frame pointers are enabled. Specifically, jmpdefer manipulates the SP as if its own caller, deferreturn, had returned. However, it does not manipulate the BP to match. As a result, when a BP-based traceback happens during a deferred function call, it unwinds to the function that performed the defer and then thinks that function called itself in an infinite regress. Fix this by making jmpdefer manipulate the BP as if deferreturn had actually returned. Fixes #12968. Updates #15840. Change-Id: Ic9cc7c863baeaf977883ed0c25a7e80e592cf066 Reviewed-on: https://go-review.googlesource.com/23457 Reviewed-by: Russ Cox Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot --- src/runtime/asm_amd64.s | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index d6e54941805b4a..e50c44304441de 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -526,6 +526,7 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 MOVQ fv+0(FP), DX // fn MOVQ argp+8(FP), BX // caller sp LEAQ -8(BX), SP // caller sp after CALL + MOVQ -8(SP), BP // restore BP as if deferreturn returned (harmless if framepointers not in use) SUBQ $5, (SP) // return to CALL again MOVQ 0(DX), BX JMP BX // but first run the deferred function From 6247ca2dbbdc13d6c80666119d182e119a2e7a5b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 26 May 2016 09:59:29 -0400 Subject: [PATCH 237/267] cmd/dist: drop testcarchive on ppc64le It is timing out on the dashboard. (We enabled it as an experiment to see if it was still broken. Looks that way.) Change-Id: I425b7e54a2ab95b623ab7a15554b4173078f75e2 Reviewed-on: https://go-review.googlesource.com/23480 Reviewed-by: Russ Cox --- src/cmd/dist/test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 366b3af9ae7a57..69a13ddf9d3630 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -680,8 +680,7 @@ func (t *tester) supportedBuildmode(mode string) bool { } switch pair { case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", - "linux-amd64", "linux-386", "windows-amd64", "windows-386", - "linux-ppc64le": + "linux-amd64", "linux-386", "windows-amd64", "windows-386": return true } return false From 56e5e0b69c92c9157c7db39112e27a4b5c026b48 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 25 May 2016 13:19:11 -0400 Subject: [PATCH 238/267] runtime: tell race detector about reflectOffs.lock Fixes #15832 Change-Id: I6f3f45e3c21edd0e093ecb1d8a067907863478f5 Reviewed-on: https://go-review.googlesource.com/23441 Reviewed-by: Dmitry Vyukov --- src/reflect/all_test.go | 15 +++++++++++++++ src/reflect/export_test.go | 4 ++++ src/runtime/runtime1.go | 4 ++-- src/runtime/type.go | 26 ++++++++++++++++++++------ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index c801bfc1ec559f..f7cf46daecf524 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -5722,3 +5722,18 @@ func TestTypeStrings(t *testing.T) { } } } + +func TestOffsetLock(t *testing.T) { + var wg sync.WaitGroup + for i := 0; i < 4; i++ { + i := i + wg.Add(1) + go func() { + for j := 0; j < 50; j++ { + ResolveReflectName(fmt.Sprintf("OffsetLockName:%d:%d", i, j)) + } + wg.Done() + }() + } + wg.Wait() +} diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 00189f3353f196..2cc1530250c084 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -109,3 +109,7 @@ func IsExported(t Type) bool { n := typ.nameOff(typ.str) return n.isExported() } + +func ResolveReflectName(s string) { + resolveReflectName(newName(s, "", "", false)) +} diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 90893839045119..302f58de5fa91a 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -509,7 +509,7 @@ func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { // reflect_addReflectOff adds a pointer to the reflection offset lookup map. //go:linkname reflect_addReflectOff reflect.addReflectOff func reflect_addReflectOff(ptr unsafe.Pointer) int32 { - lock(&reflectOffs.lock) + reflectOffsLock() if reflectOffs.m == nil { reflectOffs.m = make(map[int32]unsafe.Pointer) reflectOffs.minv = make(map[unsafe.Pointer]int32) @@ -522,6 +522,6 @@ func reflect_addReflectOff(ptr unsafe.Pointer) int32 { reflectOffs.m[id] = ptr reflectOffs.minv[ptr] = id } - unlock(&reflectOffs.lock) + reflectOffsUnlock() return id } diff --git a/src/runtime/type.go b/src/runtime/type.go index 608c601abd2973..d7ec5573a9d851 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -169,6 +169,20 @@ var reflectOffs struct { minv map[unsafe.Pointer]int32 } +func reflectOffsLock() { + lock(&reflectOffs.lock) + if raceenabled { + raceacquire(unsafe.Pointer(&reflectOffs.lock)) + } +} + +func reflectOffsUnlock() { + if raceenabled { + racerelease(unsafe.Pointer(&reflectOffs.lock)) + } + unlock(&reflectOffs.lock) +} + func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { if off == 0 { return name{} @@ -182,9 +196,9 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { } } if md == nil { - lock(&reflectOffs.lock) + reflectOffsLock() res, found := reflectOffs.m[int32(off)] - unlock(&reflectOffs.lock) + reflectOffsUnlock() if !found { println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") for next := &firstmoduledata; next != nil; next = next.next { @@ -219,9 +233,9 @@ func (t *_type) typeOff(off typeOff) *_type { } } if md == nil { - lock(&reflectOffs.lock) + reflectOffsLock() res := reflectOffs.m[int32(off)] - unlock(&reflectOffs.lock) + reflectOffsUnlock() if res == nil { println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") for next := &firstmoduledata; next != nil; next = next.next { @@ -252,9 +266,9 @@ func (t *_type) textOff(off textOff) unsafe.Pointer { } } if md == nil { - lock(&reflectOffs.lock) + reflectOffsLock() res := reflectOffs.m[int32(off)] - unlock(&reflectOffs.lock) + reflectOffsUnlock() if res == nil { println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") for next := &firstmoduledata; next != nil; next = next.next { From 2168f2a68bb438996d14869ff7dd10a47cc0552c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 25 May 2016 17:29:56 -0700 Subject: [PATCH 239/267] math/big: simplify benchmarking code some more Follow-up cleanup to https://golang.org/cl/23424/ . Change-Id: Ifb05c1ff5327df6bc5f4cbc554e18363293f7960 Reviewed-on: https://go-review.googlesource.com/23446 Reviewed-by: Marcel van Lohuizen --- src/math/big/arith_test.go | 48 ++++++++++++++------------------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go index 94e5f5ca8757e7..75862b4951fffe 100644 --- a/src/math/big/arith_test.go +++ b/src/math/big/arith_test.go @@ -119,29 +119,15 @@ func rndV(n int) []Word { return v } -var benchSizes = []struct { - name string - n int -}{ - {"1", 1}, - {"2", 2}, - {"3", 3}, - {"4", 4}, - {"5", 5}, - {"1e1", 1e1}, - {"1e2", 1e2}, - {"1e3", 1e3}, - {"1e4", 1e4}, - {"1e5", 1e5}, -} +var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5} func BenchmarkAddVV(b *testing.B) { - for _, tc := range benchSizes { - x := rndV(tc.n) - y := rndV(tc.n) - z := make([]Word, tc.n) - b.Run(fmt.Sprint(tc.name), func(b *testing.B) { - b.SetBytes(int64(tc.n * _W)) + for _, n := range benchSizes { + x := rndV(n) + y := rndV(n) + z := make([]Word, n) + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n * _W)) for i := 0; i < b.N; i++ { addVV(z, x, y) } @@ -246,12 +232,12 @@ func TestFunVW(t *testing.T) { } func BenchmarkAddVW(b *testing.B) { - for _, tc := range benchSizes { - x := rndV(tc.n) + for _, n := range benchSizes { + x := rndV(n) y := rndW() - z := make([]Word, tc.n) - b.Run(fmt.Sprint(tc.name), func(b *testing.B) { - b.SetBytes(int64(tc.n * _S)) + z := make([]Word, n) + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n * _S)) for i := 0; i < b.N; i++ { addVW(z, x, y) } @@ -384,12 +370,12 @@ func TestMulAddWWW(t *testing.T) { } func BenchmarkAddMulVVW(b *testing.B) { - for _, tc := range benchSizes { - x := rndV(tc.n) + for _, n := range benchSizes { + x := rndV(n) y := rndW() - z := make([]Word, tc.n) - b.Run(fmt.Sprint(tc.n), func(b *testing.B) { - b.SetBytes(int64(tc.n * _W)) + z := make([]Word, n) + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n * _W)) for i := 0; i < b.N; i++ { addMulVVW(z, x, y) } From 7fdec6216c0a25c6dbcc8159b755da6682dd9080 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 14:37:43 -0400 Subject: [PATCH 240/267] build: enable framepointer mode by default This has a minor performance cost, but far less than is being gained by SSA. As an experiment, enable it during the Go 1.7 beta. Having frame pointers on by default makes Linux's perf, Intel VTune, and other profilers much more useful, because it lets them gather a stack trace efficiently on profiling events. (It doesn't help us that much, since when we walk the stack we usually need to look up PC-specific information as well.) Fixes #15840. Change-Id: I4efd38412a0de4a9c87b1b6e5d11c301e63f1a2a Reviewed-on: https://go-review.googlesource.com/23451 Run-TryBot: Russ Cox Reviewed-by: Austin Clements TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/amd64/galign.go | 15 ++++++--------- src/cmd/compile/internal/amd64/reg.go | 3 +-- src/cmd/compile/internal/ssa/regalloc.go | 3 +-- src/cmd/internal/obj/go.go | 20 ++++++++++++++++---- src/cmd/internal/obj/link.go | 2 ++ src/cmd/internal/obj/sym.go | 1 + src/cmd/internal/obj/x86/asm6.go | 4 ++-- src/cmd/internal/obj/x86/obj6.go | 2 +- src/cmd/link/internal/ld/dwarf.go | 2 +- src/cmd/link/internal/ld/lib.go | 8 +++++++- src/runtime/proc.go | 9 ++++++--- src/runtime/runtime2.go | 3 ++- src/runtime/stack.go | 3 --- 13 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index 461ef2ada1bb32..42915340a06bf8 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -25,18 +25,16 @@ func betypeinit() { cmpptr = x86.ACMPL } - if gc.Ctxt.Flag_dynlink { - gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, x86.REG_R15) + if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" { + resvd = append(resvd, x86.REG_R15) } -} - -func Main() { - if obj.Getgoos() == "nacl" { - resvd = append(resvd, x86.REG_BP, x86.REG_R15) - } else if obj.Framepointer_enabled != 0 { + if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" { resvd = append(resvd, x86.REG_BP) } + gc.Thearch.ReservedRegs = resvd +} +func Main() { gc.Thearch.LinkArch = &x86.Linkamd64 if obj.Getgoarch() == "amd64p32" { gc.Thearch.LinkArch = &x86.Linkamd64p32 @@ -51,7 +49,6 @@ func Main() { gc.Thearch.FREGMIN = x86.REG_X0 gc.Thearch.FREGMAX = x86.REG_X15 gc.Thearch.MAXWIDTH = 1 << 50 - gc.Thearch.ReservedRegs = resvd gc.Thearch.AddIndex = addindex gc.Thearch.Betypeinit = betypeinit diff --git a/src/cmd/compile/internal/amd64/reg.go b/src/cmd/compile/internal/amd64/reg.go index 764f5c3a9e6380..77720c855f13f1 100644 --- a/src/cmd/compile/internal/amd64/reg.go +++ b/src/cmd/compile/internal/amd64/reg.go @@ -32,7 +32,6 @@ package amd64 import ( "cmd/compile/internal/gc" - "cmd/internal/obj" "cmd/internal/obj/x86" ) @@ -121,7 +120,7 @@ func BtoR(b uint64) int { b &= 0xffff if gc.Nacl { b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX)) - } else if obj.Framepointer_enabled != 0 { + } else if gc.Ctxt.Framepointer_enabled { // BP is part of the calling convention if framepointer_enabled. b &^= (1 << (x86.REG_BP - x86.REG_AX)) } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index bd405225746e70..1eecd49c40cf3a 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -106,7 +106,6 @@ package ssa import ( - "cmd/internal/obj" "fmt" "unsafe" ) @@ -456,7 +455,7 @@ func (s *regAllocState) init(f *Func) { s.allocatable = regMask(1)< 2 && name[:2] == "no" { + v = 0 + name = name[2:] + } for i := 0; i < len(exper); i++ { - if exper[i].name == s { + if exper[i].name == name { if exper[i].val != nil { - *exper[i].val = 1 + *exper[i].val = v } return } @@ -44,6 +51,7 @@ func addexp(s string) { } func init() { + framepointer_enabled = 1 // default for _, f := range strings.Split(goexperiment, ",") { if f != "" { addexp(f) @@ -51,6 +59,10 @@ func init() { } } +func Framepointer_enabled(goos, goarch string) bool { + return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl" +} + func Nopout(p *Prog) { p.As = ANOP p.Scond = 0 diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index eaf702533a141f..b6861f4c1e572c 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -664,6 +664,8 @@ type Link struct { Etextp *LSym Errors int + Framepointer_enabled bool + // state for writing objects Text []*LSym Data []*LSym diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index 6f3542b3d4f421..e974ca8c8af306 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -106,6 +106,7 @@ func Linknew(arch *LinkArch) *Link { } ctxt.Flag_optimize = true + ctxt.Framepointer_enabled = Framepointer_enabled(Getgoos(), arch.Name) return ctxt } diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 9230c9fdacb1da..414a4d34a558c5 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -3765,7 +3765,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { ctxt.Diag("directly calling duff when dynamically linking Go") } - if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 { + if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 { // Maintain BP around call, since duffcopy/duffzero can't do it // (the call jumps into the middle of the function). // This makes it possible to see call sites for duffcopy/duffzero in @@ -3784,7 +3784,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { r.Siz = 4 ctxt.AsmBuf.PutInt32(0) - if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 { + if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 { // Pop BP pushed above. // MOVQ 0(BP), BP ctxt.AsmBuf.Put(bpduff2) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 0f1f28d36d6d94..5dad0bbb982616 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -610,7 +610,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) { } var bpsize int - if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 0 { + if p.Mode == 64 && ctxt.Framepointer_enabled && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 0 { // Make room for to save a base pointer. If autoffset == 0, // this might do something special like a tail jump to // another function, so in that case we omit this. diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index ca86e72d8329cc..01747c543017a7 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1558,7 +1558,7 @@ func writelines(prev *LSym) *LSym { if !haslinkregister() { offs -= int64(SysArch.PtrSize) } - if obj.Framepointer_enabled != 0 { + if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) { // The frame pointer is saved // between the CFA and the // autos. diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index da00de8547c748..bab71fb3114376 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -639,11 +639,17 @@ func loadlib() { // recording the value of GOARM. if SysArch.Family == sys.ARM { s := Linklookup(Ctxt, "runtime.goarm", 0) - s.Type = obj.SRODATA s.Size = 0 Adduint8(Ctxt, s, uint8(Ctxt.Goarm)) } + + if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) { + s := Linklookup(Ctxt, "runtime.framepointer_enabled", 0) + s.Type = obj.SRODATA + s.Size = 0 + Adduint8(Ctxt, s, 1) + } } else { // If OTOH the module does not contain the runtime package, // create a local symbol for the moduledata. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index ee895471046e62..727c991a577c1c 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -434,9 +434,6 @@ func schedinit() { sched.maxmcount = 10000 - // Cache the framepointer experiment. This affects stack unwinding. - framepointer_enabled = haveexperiment("framepointer") - tracebackinit() moduledataverify() stackinit() @@ -4163,6 +4160,9 @@ func setMaxThreads(in int) (out int) { } func haveexperiment(name string) bool { + if name == "framepointer" { + return framepointer_enabled // set by linker + } x := sys.Goexperiment for x != "" { xname := "" @@ -4175,6 +4175,9 @@ func haveexperiment(name string) bool { if xname == name { return true } + if len(xname) > 2 && xname[:2] == "no" && xname[2:] == name { + return false + } } return false } diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 71da504f1c0e19..6119e75203c457 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -725,7 +725,8 @@ var ( support_avx bool support_avx2 bool - goarm uint8 // set by cmd/link on arm systems + goarm uint8 // set by cmd/link on arm systems + framepointer_enabled bool // set by cmd/link ) // Set by the linker so the runtime can determine the buildmode. diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 33d29f19a8cedc..8e344cdf03585c 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -155,9 +155,6 @@ var stackLarge struct { free [_MHeapMap_Bits]mSpanList // free lists by log_2(s.npages) } -// Cached value of haveexperiment("framepointer") -var framepointer_enabled bool - func stackinit() { if _StackCacheSize&_PageMask != 0 { throw("cache size must be a multiple of page size") From bfccf4071eb9401cb906b203659010f9422c524f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 26 May 2016 15:02:55 -0400 Subject: [PATCH 241/267] cmd/dist: drop ppc64le from testcshared I'm glad my CL fixed the library use case inside Google. It fixes neither of the two tests here. Change-Id: Ica91722dced8955a0a8ba3aad3d288816b46564e Reviewed-on: https://go-review.googlesource.com/23482 Run-TryBot: Russ Cox Reviewed-by: Russ Cox --- src/cmd/dist/test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 69a13ddf9d3630..1a1f7d961bea77 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -688,8 +688,7 @@ func (t *tester) supportedBuildmode(mode string) bool { switch pair { case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "darwin-amd64", "darwin-386", - "android-arm", "android-arm64", "android-386", - "linux-ppc64le": + "android-arm", "android-arm64", "android-386": return true } return false From 2deb9209dec81792156c8e865a409a4ee5c331f6 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Thu, 26 May 2016 11:29:53 +0200 Subject: [PATCH 242/267] math/big: using Run for some more benchmarks Change-Id: I3ede8098f405de5d88e51c8370d3b68446d40744 Reviewed-on: https://go-review.googlesource.com/23428 Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/math/big/nat_test.go | 27 ++++--- src/math/big/natconv_test.go | 133 ++++++++++++----------------------- 2 files changed, 57 insertions(+), 103 deletions(-) diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go index 563ccb30523ada..ebb29856549b8e 100644 --- a/src/math/big/nat_test.go +++ b/src/math/big/nat_test.go @@ -5,6 +5,7 @@ package big import ( + "fmt" "runtime" "strings" "testing" @@ -509,24 +510,20 @@ func TestExpNN(t *testing.T) { } } -func ExpHelper(b *testing.B, x, y Word) { - var z nat - for i := 0; i < b.N; i++ { - z.expWW(x, y) +func BenchmarkExp3Power(b *testing.B) { + const x = 3 + for _, y := range []Word{ + 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, + } { + b.Run(fmt.Sprintf("%#x", y), func(b *testing.B) { + var z nat + for i := 0; i < b.N; i++ { + z.expWW(x, y) + } + }) } } -func BenchmarkExp3Power0x10(b *testing.B) { ExpHelper(b, 3, 0x10) } -func BenchmarkExp3Power0x40(b *testing.B) { ExpHelper(b, 3, 0x40) } -func BenchmarkExp3Power0x100(b *testing.B) { ExpHelper(b, 3, 0x100) } -func BenchmarkExp3Power0x400(b *testing.B) { ExpHelper(b, 3, 0x400) } -func BenchmarkExp3Power0x1000(b *testing.B) { ExpHelper(b, 3, 0x1000) } -func BenchmarkExp3Power0x4000(b *testing.B) { ExpHelper(b, 3, 0x4000) } -func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) } -func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) } -func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) } -func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) } - func fibo(n int) nat { switch n { case 0: diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go index 028e5a858eb98c..79901d1880477f 100644 --- a/src/math/big/natconv_test.go +++ b/src/math/big/natconv_test.go @@ -6,6 +6,7 @@ package big import ( "bytes" + "fmt" "io" "strings" "testing" @@ -273,102 +274,58 @@ func BenchmarkStringPiParallel(b *testing.B) { }) } -func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) } -func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) } -func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) } -func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) } -func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) } - -func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) } -func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) } -func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) } -func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) } -func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) } - -func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) } -func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) } -func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) } -func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) } -func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) } - -func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) } -func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) } -func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) } -func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) } -func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) } - -func ScanHelper(b *testing.B, base int, x, y Word) { - b.StopTimer() - var z nat - z = z.expWW(x, y) - - s := z.utoa(base) - if t := itoa(z, base); !bytes.Equal(s, t) { - b.Fatalf("scanning: got %s; want %s", s, t) +func BenchmarkScan(b *testing.B) { + const x = 10 + for _, base := range []int{2, 8, 10, 16} { + for _, y := range []Word{10, 100, 1000, 10000, 100000} { + b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) { + b.StopTimer() + var z nat + z = z.expWW(x, y) + + s := z.utoa(base) + if t := itoa(z, base); !bytes.Equal(s, t) { + b.Fatalf("scanning: got %s; want %s", s, t) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + z.scan(bytes.NewReader(s), base, false) + } + }) + } } - b.StartTimer() +} - for i := 0; i < b.N; i++ { - z.scan(bytes.NewReader(s), base, false) +func BenchmarkString(b *testing.B) { + const x = 10 + for _, base := range []int{2, 8, 10, 16} { + for _, y := range []Word{10, 100, 1000, 10000, 100000} { + b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) { + b.StopTimer() + var z nat + z = z.expWW(x, y) + z.utoa(base) // warm divisor cache + b.StartTimer() + + for i := 0; i < b.N; i++ { + _ = z.utoa(base) + } + }) + } } } -func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) } -func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) } -func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) } -func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) } -func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) } - -func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) } -func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) } -func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) } -func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) } -func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) } - -func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) } -func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) } -func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) } -func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) } -func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) } - -func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) } -func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) } -func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) } -func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) } -func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) } - -func StringHelper(b *testing.B, base int, x, y Word) { - b.StopTimer() - var z nat - z = z.expWW(x, y) - z.utoa(base) // warm divisor cache - b.StartTimer() - - for i := 0; i < b.N; i++ { - _ = z.utoa(base) +func BenchmarkLeafSize(b *testing.B) { + for n := 0; n <= 16; n++ { + b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) }) + } + // Try some large lengths + for _, n := range []int{32, 64} { + b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) }) } } -func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting -func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) } -func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) } -func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) } -func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) } -func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) } -func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) } -func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) } -func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) } -func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) } -func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) } -func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) } -func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) } -func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) } -func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) } -func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) } -func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) } -func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths -func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) } - func LeafSizeHelper(b *testing.B, base, size int) { b.StopTimer() originalLeafSize := leafSize From 13a5b1faee06b59df456930d04edd2b5e083b019 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 26 May 2016 12:16:53 -0700 Subject: [PATCH 243/267] cmd/compile: improve domorder documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit domorder has some non-obvious useful properties that we’re relying on in cse. Document them and provide an argument that they hold. While we’re here, do some minor renaming. The argument is a re-working of a private email exchange with Todd Neal and David Chase. Change-Id: Ie154e0521bde642f5f11e67fc542c5eb938258be Reviewed-on: https://go-review.googlesource.com/23449 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/cse.go | 19 +++++------- src/cmd/compile/internal/ssa/sparsetree.go | 36 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index 20ea45ab3e139a..ad4e4161591d0a 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -137,10 +137,9 @@ func cse(f *Func) { // if v and w are in the same equivalence class and v dominates w. rewrite := make([]*Value, f.NumValues()) for _, e := range partition { - sort.Sort(sortbyentry{e, f.sdom}) + sort.Sort(partitionByDom{e, f.sdom}) for i := 0; i < len(e)-1; i++ { - // e is sorted by entry value so maximal dominant element should be - // found first in the slice + // e is sorted by domorder, so a maximal dominant element is first in the slice v := e[i] if v == nil { continue @@ -157,9 +156,7 @@ func cse(f *Func) { rewrite[w.ID] = v e[j] = nil } else { - // since the blocks are assorted in ascending order by entry number - // once we know that we don't dominate a block we can't dominate any - // 'later' block + // e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e break } } @@ -311,15 +308,15 @@ func (sv sortvalues) Less(i, j int) bool { return v.ID < w.ID } -type sortbyentry struct { +type partitionByDom struct { a []*Value // array of values sdom SparseTree } -func (sv sortbyentry) Len() int { return len(sv.a) } -func (sv sortbyentry) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] } -func (sv sortbyentry) Less(i, j int) bool { +func (sv partitionByDom) Len() int { return len(sv.a) } +func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] } +func (sv partitionByDom) Less(i, j int) bool { v := sv.a[i] w := sv.a[j] - return sv.sdom.maxdomorder(v.Block) < sv.sdom.maxdomorder(w.Block) + return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block) } diff --git a/src/cmd/compile/internal/ssa/sparsetree.go b/src/cmd/compile/internal/ssa/sparsetree.go index 21fe68601eab3f..7c82a60d0fa8fc 100644 --- a/src/cmd/compile/internal/ssa/sparsetree.go +++ b/src/cmd/compile/internal/ssa/sparsetree.go @@ -149,8 +149,38 @@ func (t SparseTree) isAncestor(x, y *Block) bool { return xx.entry < yy.entry && yy.exit < xx.exit } -// maxdomorder returns a value to allow a maximal dominator first sort. maxdomorder(x) < maxdomorder(y) is true -// if x may dominate y, and false if x cannot dominate y. -func (t SparseTree) maxdomorder(x *Block) int32 { +// domorder returns a value for dominator-oriented sorting. +// Block domination does not provide a total ordering, +// but domorder two has useful properties. +// (1) If domorder(x) > domorder(y) then x does not dominate y. +// (2) If domorder(x) < domorder(y) and domorder(y) < domorder(z) and x does not dominate y, +// then x does not dominate z. +// Property (1) means that blocks sorted by domorder always have a maximal dominant block first. +// Property (2) allows searches for dominated blocks to exit early. +func (t SparseTree) domorder(x *Block) int32 { + // Here is an argument that entry(x) provides the properties documented above. + // + // Entry and exit values are assigned in a depth-first dominator tree walk. + // For all blocks x and y, one of the following holds: + // + // (x-dom-y) x dominates y => entry(x) < entry(y) < exit(y) < exit(x) + // (y-dom-x) y dominates x => entry(y) < entry(x) < exit(x) < exit(y) + // (x-then-y) neither x nor y dominates the other and x walked before y => entry(x) < exit(x) < entry(y) < exit(y) + // (y-then-x) neither x nor y dominates the other and y walked before y => entry(y) < exit(y) < entry(x) < exit(x) + // + // entry(x) > entry(y) eliminates case x-dom-y. This provides property (1) above. + // + // For property (2), assume entry(x) < entry(y) and entry(y) < entry(z) and x does not dominate y. + // entry(x) < entry(y) allows cases x-dom-y and x-then-y. + // But by supposition, x does not dominate y. So we have x-then-y. + // + // For contractidion, assume x dominates z. + // Then entry(x) < entry(z) < exit(z) < exit(x). + // But we know x-then-y, so entry(x) < exit(x) < entry(y) < exit(y). + // Combining those, entry(x) < entry(z) < exit(z) < exit(x) < entry(y) < exit(y). + // By supposition, entry(y) < entry(z), which allows cases y-dom-z and y-then-z. + // y-dom-z requires entry(y) < entry(z), but we have entry(z) < entry(y). + // y-then-z requires exit(y) < entry(z), but we have entry(z) < exit(y). + // We have a contradiction, so x does not dominate z, as required. return t[x.ID].entry } From 0e930015c16b73dc9f98776b6624f02ea41d8268 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 24 May 2016 15:43:25 -0700 Subject: [PATCH 244/267] cmd/compile: log rules to a file for rule coverage tool When rules are generated with -log, log rule application to a file. The file is opened in append mode so multiple calls to the compiler union their logs. Change-Id: Ib35c7c85bf58e5909ea9231043f8cbaa6bf278b7 Reviewed-on: https://go-review.googlesource.com/23406 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/gen/rulegen.go | 7 ++---- src/cmd/compile/internal/ssa/rewrite.go | 27 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index fcabdb1dd908d9..0fc5749f1d5aa6 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -150,9 +150,6 @@ func genRules(arch arch) { fmt.Fprintln(w, "// generated with: cd gen; go run *.go") fmt.Fprintln(w) fmt.Fprintln(w, "package ssa") - if *genLog { - fmt.Fprintln(w, "import \"fmt\"") - } fmt.Fprintln(w, "import \"math\"") fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used") @@ -196,7 +193,7 @@ func genRules(arch arch) { genResult(w, arch, result, rule.loc) if *genLog { - fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc) + fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc) } fmt.Fprintf(w, "return true\n") @@ -300,7 +297,7 @@ func genRules(arch arch) { } if *genLog { - fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc) + fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc) } fmt.Fprintf(w, "return true\n") diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 7d6d2179f76425..03c38827cc433e 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -7,6 +7,8 @@ package ssa import ( "fmt" "math" + "os" + "path/filepath" ) func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) { @@ -357,3 +359,28 @@ func clobber(v *Value) bool { // Note: leave v.Block intact. The Block field is used after clobber. return true } + +// logRule logs the use of the rule s. This will only be enabled if +// rewrite rules were generated with the -log option, see gen/rulegen.go. +func logRule(s string) { + if ruleFile == nil { + // Open a log file to write log to. We open in append + // mode because all.bash runs the compiler lots of times, + // and we want the concatenation of all of those logs. + // This means, of course, that users need to rm the old log + // to get fresh data. + // TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow? + w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"), + os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + panic(err) + } + ruleFile = w + } + _, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s) + if err != nil { + panic(err) + } +} + +var ruleFile *os.File From 02bf6b5ef93cdb981949e8164e4364a9d8424dc9 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 26 May 2016 14:31:35 -0700 Subject: [PATCH 245/267] cmd/compile: add tests for logical simplification rewrite rules Increases coverage of generic.rules from 72% to 84%. Change-Id: I1b139aeeb6410d025d49cbe4e4601f6f935ce1e5 Reviewed-on: https://go-review.googlesource.com/23490 Reviewed-by: Todd Neal --- src/cmd/compile/internal/gc/logic_test.go | 289 ++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/cmd/compile/internal/gc/logic_test.go diff --git a/src/cmd/compile/internal/gc/logic_test.go b/src/cmd/compile/internal/gc/logic_test.go new file mode 100644 index 00000000000000..78d2dd2fa81fad --- /dev/null +++ b/src/cmd/compile/internal/gc/logic_test.go @@ -0,0 +1,289 @@ +package gc + +import "testing" + +// Tests to make sure logic simplification rules are correct. + +func TestLogic64(t *testing.T) { + // test values to determine function equality + values := [...]int64{-1 << 63, 1<<63 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4} + + // golden functions we use repeatedly + zero := func(x int64) int64 { return 0 } + id := func(x int64) int64 { return x } + or := func(x, y int64) int64 { return x | y } + and := func(x, y int64) int64 { return x & y } + y := func(x, y int64) int64 { return y } + + for _, test := range [...]struct { + name string + f func(int64) int64 + golden func(int64) int64 + }{ + {"x|x", func(x int64) int64 { return x | x }, id}, + {"x|0", func(x int64) int64 { return x | 0 }, id}, + {"x|-1", func(x int64) int64 { return x | -1 }, func(x int64) int64 { return -1 }}, + {"x&x", func(x int64) int64 { return x & x }, id}, + {"x&0", func(x int64) int64 { return x & 0 }, zero}, + {"x&-1", func(x int64) int64 { return x & -1 }, id}, + {"x^x", func(x int64) int64 { return x ^ x }, zero}, + {"x^0", func(x int64) int64 { return x ^ 0 }, id}, + {"x^-1", func(x int64) int64 { return x ^ -1 }, func(x int64) int64 { return ^x }}, + {"x+0", func(x int64) int64 { return x + 0 }, id}, + {"x-x", func(x int64) int64 { return x - x }, zero}, + {"x*0", func(x int64) int64 { return x * 0 }, zero}, + {"^^x", func(x int64) int64 { return ^^x }, id}, + } { + for _, v := range values { + got := test.f(v) + want := test.golden(v) + if want != got { + t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want) + } + } + } + for _, test := range [...]struct { + name string + f func(int64, int64) int64 + golden func(int64, int64) int64 + }{ + {"x|(x|y)", func(x, y int64) int64 { return x | (x | y) }, or}, + {"x|(y|x)", func(x, y int64) int64 { return x | (y | x) }, or}, + {"(x|y)|x", func(x, y int64) int64 { return (x | y) | x }, or}, + {"(y|x)|x", func(x, y int64) int64 { return (y | x) | x }, or}, + {"x&(x&y)", func(x, y int64) int64 { return x & (x & y) }, and}, + {"x&(y&x)", func(x, y int64) int64 { return x & (y & x) }, and}, + {"(x&y)&x", func(x, y int64) int64 { return (x & y) & x }, and}, + {"(y&x)&x", func(x, y int64) int64 { return (y & x) & x }, and}, + {"x^(x^y)", func(x, y int64) int64 { return x ^ (x ^ y) }, y}, + {"x^(y^x)", func(x, y int64) int64 { return x ^ (y ^ x) }, y}, + {"(x^y)^x", func(x, y int64) int64 { return (x ^ y) ^ x }, y}, + {"(y^x)^x", func(x, y int64) int64 { return (y ^ x) ^ x }, y}, + {"-(y-x)", func(x, y int64) int64 { return -(y - x) }, func(x, y int64) int64 { return x - y }}, + {"(x+y)-x", func(x, y int64) int64 { return (x + y) - x }, y}, + {"(y+x)-x", func(x, y int64) int64 { return (y + x) - x }, y}, + } { + for _, v := range values { + for _, w := range values { + got := test.f(v, w) + want := test.golden(v, w) + if want != got { + t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want) + } + } + } + } +} + +func TestLogic32(t *testing.T) { + // test values to determine function equality + values := [...]int32{-1 << 31, 1<<31 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4} + + // golden functions we use repeatedly + zero := func(x int32) int32 { return 0 } + id := func(x int32) int32 { return x } + or := func(x, y int32) int32 { return x | y } + and := func(x, y int32) int32 { return x & y } + y := func(x, y int32) int32 { return y } + + for _, test := range [...]struct { + name string + f func(int32) int32 + golden func(int32) int32 + }{ + {"x|x", func(x int32) int32 { return x | x }, id}, + {"x|0", func(x int32) int32 { return x | 0 }, id}, + {"x|-1", func(x int32) int32 { return x | -1 }, func(x int32) int32 { return -1 }}, + {"x&x", func(x int32) int32 { return x & x }, id}, + {"x&0", func(x int32) int32 { return x & 0 }, zero}, + {"x&-1", func(x int32) int32 { return x & -1 }, id}, + {"x^x", func(x int32) int32 { return x ^ x }, zero}, + {"x^0", func(x int32) int32 { return x ^ 0 }, id}, + {"x^-1", func(x int32) int32 { return x ^ -1 }, func(x int32) int32 { return ^x }}, + {"x+0", func(x int32) int32 { return x + 0 }, id}, + {"x-x", func(x int32) int32 { return x - x }, zero}, + {"x*0", func(x int32) int32 { return x * 0 }, zero}, + {"^^x", func(x int32) int32 { return ^^x }, id}, + } { + for _, v := range values { + got := test.f(v) + want := test.golden(v) + if want != got { + t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want) + } + } + } + for _, test := range [...]struct { + name string + f func(int32, int32) int32 + golden func(int32, int32) int32 + }{ + {"x|(x|y)", func(x, y int32) int32 { return x | (x | y) }, or}, + {"x|(y|x)", func(x, y int32) int32 { return x | (y | x) }, or}, + {"(x|y)|x", func(x, y int32) int32 { return (x | y) | x }, or}, + {"(y|x)|x", func(x, y int32) int32 { return (y | x) | x }, or}, + {"x&(x&y)", func(x, y int32) int32 { return x & (x & y) }, and}, + {"x&(y&x)", func(x, y int32) int32 { return x & (y & x) }, and}, + {"(x&y)&x", func(x, y int32) int32 { return (x & y) & x }, and}, + {"(y&x)&x", func(x, y int32) int32 { return (y & x) & x }, and}, + {"x^(x^y)", func(x, y int32) int32 { return x ^ (x ^ y) }, y}, + {"x^(y^x)", func(x, y int32) int32 { return x ^ (y ^ x) }, y}, + {"(x^y)^x", func(x, y int32) int32 { return (x ^ y) ^ x }, y}, + {"(y^x)^x", func(x, y int32) int32 { return (y ^ x) ^ x }, y}, + {"-(y-x)", func(x, y int32) int32 { return -(y - x) }, func(x, y int32) int32 { return x - y }}, + {"(x+y)-x", func(x, y int32) int32 { return (x + y) - x }, y}, + {"(y+x)-x", func(x, y int32) int32 { return (y + x) - x }, y}, + } { + for _, v := range values { + for _, w := range values { + got := test.f(v, w) + want := test.golden(v, w) + if want != got { + t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want) + } + } + } + } +} + +func TestLogic16(t *testing.T) { + // test values to determine function equality + values := [...]int16{-1 << 15, 1<<15 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4} + + // golden functions we use repeatedly + zero := func(x int16) int16 { return 0 } + id := func(x int16) int16 { return x } + or := func(x, y int16) int16 { return x | y } + and := func(x, y int16) int16 { return x & y } + y := func(x, y int16) int16 { return y } + + for _, test := range [...]struct { + name string + f func(int16) int16 + golden func(int16) int16 + }{ + {"x|x", func(x int16) int16 { return x | x }, id}, + {"x|0", func(x int16) int16 { return x | 0 }, id}, + {"x|-1", func(x int16) int16 { return x | -1 }, func(x int16) int16 { return -1 }}, + {"x&x", func(x int16) int16 { return x & x }, id}, + {"x&0", func(x int16) int16 { return x & 0 }, zero}, + {"x&-1", func(x int16) int16 { return x & -1 }, id}, + {"x^x", func(x int16) int16 { return x ^ x }, zero}, + {"x^0", func(x int16) int16 { return x ^ 0 }, id}, + {"x^-1", func(x int16) int16 { return x ^ -1 }, func(x int16) int16 { return ^x }}, + {"x+0", func(x int16) int16 { return x + 0 }, id}, + {"x-x", func(x int16) int16 { return x - x }, zero}, + {"x*0", func(x int16) int16 { return x * 0 }, zero}, + {"^^x", func(x int16) int16 { return ^^x }, id}, + } { + for _, v := range values { + got := test.f(v) + want := test.golden(v) + if want != got { + t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want) + } + } + } + for _, test := range [...]struct { + name string + f func(int16, int16) int16 + golden func(int16, int16) int16 + }{ + {"x|(x|y)", func(x, y int16) int16 { return x | (x | y) }, or}, + {"x|(y|x)", func(x, y int16) int16 { return x | (y | x) }, or}, + {"(x|y)|x", func(x, y int16) int16 { return (x | y) | x }, or}, + {"(y|x)|x", func(x, y int16) int16 { return (y | x) | x }, or}, + {"x&(x&y)", func(x, y int16) int16 { return x & (x & y) }, and}, + {"x&(y&x)", func(x, y int16) int16 { return x & (y & x) }, and}, + {"(x&y)&x", func(x, y int16) int16 { return (x & y) & x }, and}, + {"(y&x)&x", func(x, y int16) int16 { return (y & x) & x }, and}, + {"x^(x^y)", func(x, y int16) int16 { return x ^ (x ^ y) }, y}, + {"x^(y^x)", func(x, y int16) int16 { return x ^ (y ^ x) }, y}, + {"(x^y)^x", func(x, y int16) int16 { return (x ^ y) ^ x }, y}, + {"(y^x)^x", func(x, y int16) int16 { return (y ^ x) ^ x }, y}, + {"-(y-x)", func(x, y int16) int16 { return -(y - x) }, func(x, y int16) int16 { return x - y }}, + {"(x+y)-x", func(x, y int16) int16 { return (x + y) - x }, y}, + {"(y+x)-x", func(x, y int16) int16 { return (y + x) - x }, y}, + } { + for _, v := range values { + for _, w := range values { + got := test.f(v, w) + want := test.golden(v, w) + if want != got { + t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want) + } + } + } + } +} + +func TestLogic8(t *testing.T) { + // test values to determine function equality + values := [...]int8{-1 << 7, 1<<7 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4} + + // golden functions we use repeatedly + zero := func(x int8) int8 { return 0 } + id := func(x int8) int8 { return x } + or := func(x, y int8) int8 { return x | y } + and := func(x, y int8) int8 { return x & y } + y := func(x, y int8) int8 { return y } + + for _, test := range [...]struct { + name string + f func(int8) int8 + golden func(int8) int8 + }{ + {"x|x", func(x int8) int8 { return x | x }, id}, + {"x|0", func(x int8) int8 { return x | 0 }, id}, + {"x|-1", func(x int8) int8 { return x | -1 }, func(x int8) int8 { return -1 }}, + {"x&x", func(x int8) int8 { return x & x }, id}, + {"x&0", func(x int8) int8 { return x & 0 }, zero}, + {"x&-1", func(x int8) int8 { return x & -1 }, id}, + {"x^x", func(x int8) int8 { return x ^ x }, zero}, + {"x^0", func(x int8) int8 { return x ^ 0 }, id}, + {"x^-1", func(x int8) int8 { return x ^ -1 }, func(x int8) int8 { return ^x }}, + {"x+0", func(x int8) int8 { return x + 0 }, id}, + {"x-x", func(x int8) int8 { return x - x }, zero}, + {"x*0", func(x int8) int8 { return x * 0 }, zero}, + {"^^x", func(x int8) int8 { return ^^x }, id}, + } { + for _, v := range values { + got := test.f(v) + want := test.golden(v) + if want != got { + t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want) + } + } + } + for _, test := range [...]struct { + name string + f func(int8, int8) int8 + golden func(int8, int8) int8 + }{ + {"x|(x|y)", func(x, y int8) int8 { return x | (x | y) }, or}, + {"x|(y|x)", func(x, y int8) int8 { return x | (y | x) }, or}, + {"(x|y)|x", func(x, y int8) int8 { return (x | y) | x }, or}, + {"(y|x)|x", func(x, y int8) int8 { return (y | x) | x }, or}, + {"x&(x&y)", func(x, y int8) int8 { return x & (x & y) }, and}, + {"x&(y&x)", func(x, y int8) int8 { return x & (y & x) }, and}, + {"(x&y)&x", func(x, y int8) int8 { return (x & y) & x }, and}, + {"(y&x)&x", func(x, y int8) int8 { return (y & x) & x }, and}, + {"x^(x^y)", func(x, y int8) int8 { return x ^ (x ^ y) }, y}, + {"x^(y^x)", func(x, y int8) int8 { return x ^ (y ^ x) }, y}, + {"(x^y)^x", func(x, y int8) int8 { return (x ^ y) ^ x }, y}, + {"(y^x)^x", func(x, y int8) int8 { return (y ^ x) ^ x }, y}, + {"-(y-x)", func(x, y int8) int8 { return -(y - x) }, func(x, y int8) int8 { return x - y }}, + {"(x+y)-x", func(x, y int8) int8 { return (x + y) - x }, y}, + {"(y+x)-x", func(x, y int8) int8 { return (y + x) - x }, y}, + } { + for _, v := range values { + for _, w := range values { + got := test.f(v, w) + want := test.golden(v, w) + if want != got { + t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want) + } + } + } + } +} From b1894bb5cc781f1c59af727cea07ba4e84181830 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Thu, 26 May 2016 17:53:21 -0400 Subject: [PATCH 246/267] encoding/json: improve Decode example Decoding a JSON message does not touch unspecified or null fields; always use a new underlying struct to prevent old field values from sticking around. Fixes: #14640 Change-Id: Ica78c208ce104e2cdee1d4e92bf58596ea5587c8 Reviewed-on: https://go-review.googlesource.com/23483 Reviewed-by: Andrew Gerrand --- src/encoding/json/example_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go index 326bdc9540ef9b..555eff93c0ec38 100644 --- a/src/encoding/json/example_test.go +++ b/src/encoding/json/example_test.go @@ -143,10 +143,9 @@ func ExampleDecoder_Decode_stream() { } fmt.Printf("%T: %v\n", t, t) - var m Message // while the array contains values for dec.More() { - + var m Message // decode an array value (Message) err := dec.Decode(&m) if err != nil { From 9369f22b8444d4e4afd791273ae13121d2ec7a6d Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 24 May 2016 14:09:02 -0700 Subject: [PATCH 247/267] cmd/compile: testing harness for checking generated assembly Add a test which compiles a function and checks the generated assembly to make sure certain patterns are present. This test allows us to do white box tests of the compiler to make sure optimizations don't regress. Added a few simple tests for now. More to come. Change-Id: I4ab5ce5d95b9e04e7d0d9328ffae47b8d1f95e74 Reviewed-on: https://go-review.googlesource.com/23403 Reviewed-by: David Chase Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/asm_test.go | 105 ++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/cmd/compile/internal/gc/asm_test.go diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go new file mode 100644 index 00000000000000..469f0864d5c35f --- /dev/null +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -0,0 +1,105 @@ +// 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 ( + "bytes" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + "testing" +) + +// TestAssembly checks to make sure the assembly generated for +// functions contains certain expected instructions. +// Note: this test will fail if -ssa=0. +func TestAssembly(t *testing.T) { + testenv.MustHaveGoBuild(t) + if runtime.GOOS == "windows" { + // TODO: remove if we can get "go tool compile -S" to work on windows. + t.Skipf("skipping test: recursive windows compile not working") + } + dir, err := ioutil.TempDir("", "TestAssembly") + if err != nil { + t.Fatalf("could not create directory: %v", err) + } + defer os.RemoveAll(dir) + + for _, test := range asmTests { + asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function)) + // Get rid of code for "".init. Also gets rid of type algorithms & other junk. + if i := strings.Index(asm, "\n\"\".init "); i >= 0 { + asm = asm[:i+1] + } + for _, r := range test.regexps { + if b, err := regexp.MatchString(r, asm); !b || err != nil { + t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, test.function, asm) + } + } + } +} + +// compile compiles the package pkg for architecture arch and +// returns the generated assembly. dir is a scratch directory. +func compileToAsm(dir, arch, pkg string) string { + // Create source. + src := filepath.Join(dir, "test.go") + f, err := os.Create(src) + if err != nil { + panic(err) + } + f.Write([]byte(pkg)) + f.Close() + + var stdout, stderr bytes.Buffer + cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) + cmd.Env = append(cmd.Env, "GOARCH="+arch) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + panic(err) + } + if s := stderr.String(); s != "" { + panic(fmt.Errorf("Stderr = %s\nWant empty", s)) + } + return stdout.String() +} + +// template to convert a function to a full file +const template = ` +package main +%s +` + +type asmTest struct { + // architecture to compile to + arch string + // function to compile + function string + // regexps that must match the generated assembly + regexps []string +} + +var asmTests = [...]asmTest{ + {"amd64", ` +func f(x int) int { + return x * 64 +} +`, + []string{"\tSHLQ\t\\$6,"}, + }, + {"amd64", ` +func f(x int) int { + return x * 96 +}`, + []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, + }, +} From b5d18b50ac591d41cb4aab522fa9044c61b2c1e7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 May 2016 18:42:25 -0700 Subject: [PATCH 248/267] cmd/cgo: remove -O options when generating compiler errors The cgo tool generates compiler errors to find out what kind of name it is using. Turning on optimization can confuse that process by producing new unexpected messages. Fixes #14669. Change-Id: Idc8e35fd259711ecc9638566b691c11d17140325 Reviewed-on: https://go-review.googlesource.com/23231 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- misc/cgo/errors/issue14669.go | 23 +++++++++++++++++++++++ misc/cgo/errors/test.bash | 7 +++++++ src/cmd/cgo/gcc.go | 12 ++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 misc/cgo/errors/issue14669.go diff --git a/misc/cgo/errors/issue14669.go b/misc/cgo/errors/issue14669.go new file mode 100644 index 00000000000000..04d2bcb631d249 --- /dev/null +++ b/misc/cgo/errors/issue14669.go @@ -0,0 +1,23 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 14669: test that fails when build with CGO_CFLAGS selecting +// optimization. + +package p + +/* +const int E = 1; + +typedef struct s { + int c; +} s; +*/ +import "C" + +func F() { + _ = C.s{ + c: C.E, + } +} diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash index cd358a10f815e0..643d0382050285 100755 --- a/misc/cgo/errors/test.bash +++ b/misc/cgo/errors/test.bash @@ -45,6 +45,13 @@ expect issue13129.go C.ushort check issue13423.go expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble +if ! go build issue14669.go; then + exit 1 +fi +if ! CGO_CFLAGS="-O" go build issue14669.go; then + exit 1 +fi + if ! go run ptr.go; then exit 1 fi diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 97ef824c9342a7..451798244f6db2 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1243,12 +1243,20 @@ func (p *Package) gccErrors(stdin []byte) string { // TODO(rsc): require failure args := p.gccCmd() + // Optimization options can confuse the error messages; remove them. + nargs := make([]string, 0, len(args)) + for _, arg := range args { + if !strings.HasPrefix(arg, "-O") { + nargs = append(nargs, arg) + } + } + if *debugGcc { - fmt.Fprintf(os.Stderr, "$ %s < Date: Thu, 19 May 2016 15:58:40 +1000 Subject: [PATCH 249/267] path/filepath: fix globbing of c:\*dir\... pattern The problem was introduced by the recent filepath.Join change. Fixes #14949 Change-Id: I7ee52f210e12bbb1369e308e584ddb2c7766e095 Reviewed-on: https://go-review.googlesource.com/23240 TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/path/filepath/match.go | 40 ++++++-- src/path/filepath/match_test.go | 163 ++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 7 deletions(-) diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go index d64bf84fc0a9ef..2adb0c7490821e 100644 --- a/src/path/filepath/match.go +++ b/src/path/filepath/match.go @@ -240,13 +240,10 @@ func Glob(pattern string) (matches []string, err error) { } dir, file := Split(pattern) - switch dir { - case "": - dir = "." - case string(Separator): - // nothing - default: - dir = dir[0 : len(dir)-1] // chop off trailing separator + if runtime.GOOS == "windows" { + dir = cleanGlobPathWindows(dir) + } else { + dir = cleanGlobPath(dir) } if !hasMeta(dir) { @@ -267,6 +264,35 @@ func Glob(pattern string) (matches []string, err error) { return } +// cleanGlobPath prepares path for glob matching. +func cleanGlobPath(path string) string { + switch path { + case "": + return "." + case string(Separator): + // do nothing to the path + return path + default: + return path[0 : len(path)-1] // chop off trailing separator + } +} + +// cleanGlobPathWindows is windows version of cleanGlobPath. +func cleanGlobPathWindows(path string) string { + vollen := volumeNameLen(path) + switch { + case path == "": + return "." + case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/ + // do nothing to the path + return path + case vollen == len(path) && len(path) == 2: // C: + return path + "." // convert C: into C:. + default: + return path[0 : len(path)-1] // chop off trailing separator + } +} + // glob searches for files matching pattern in the directory dir // and appends them to matches. If the directory cannot be // opened, it returns the existing matches. New matches are diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go index d8bab7f4da3969..8dcfa5972e551f 100644 --- a/src/path/filepath/match_test.go +++ b/src/path/filepath/match_test.go @@ -5,10 +5,12 @@ package filepath_test import ( + "fmt" "io/ioutil" "os" . "path/filepath" "runtime" + "sort" "strings" "testing" ) @@ -209,3 +211,164 @@ func TestGlobSymlink(t *testing.T) { } } } + +type globTest struct { + pattern string + matches []string +} + +func (test *globTest) buildWant(root string) []string { + want := make([]string, 0) + for _, m := range test.matches { + want = append(want, root+FromSlash(m)) + } + sort.Strings(want) + return want +} + +func (test *globTest) globAbs(root, rootPattern string) error { + p := FromSlash(rootPattern + `\` + test.pattern) + have, err := Glob(p) + if err != nil { + return err + } + sort.Strings(have) + want := test.buildWant(root + `\`) + if strings.Join(want, "_") == strings.Join(have, "_") { + return nil + } + return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want) +} + +func (test *globTest) globRel(root string) error { + p := root + FromSlash(test.pattern) + have, err := Glob(p) + if err != nil { + return err + } + sort.Strings(have) + want := test.buildWant(root) + if strings.Join(want, "_") == strings.Join(have, "_") { + return nil + } + // try also matching version without root prefix + wantWithNoRoot := test.buildWant("") + if strings.Join(wantWithNoRoot, "_") == strings.Join(have, "_") { + return nil + } + return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want) +} + +func TestWindowsGlob(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skipf("skipping windows specific test") + } + + tmpDir, err := ioutil.TempDir("", "TestWindowsGlob") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + // /tmp may itself be a symlink + tmpDir, err = EvalSymlinks(tmpDir) + if err != nil { + t.Fatal("eval symlink for tmp dir:", err) + } + + if len(tmpDir) < 3 { + t.Fatalf("tmpDir path %q is too short", tmpDir) + } + if tmpDir[1] != ':' { + t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir) + } + + dirs := []string{ + "a", + "b", + "dir/d/bin", + } + files := []string{ + "dir/d/bin/git.exe", + } + for _, dir := range dirs { + err := os.MkdirAll(Join(tmpDir, dir), 0777) + if err != nil { + t.Fatal(err) + } + } + for _, file := range files { + err := ioutil.WriteFile(Join(tmpDir, file), nil, 0666) + if err != nil { + t.Fatal(err) + } + } + + tests := []globTest{ + {"a", []string{"a"}}, + {"b", []string{"b"}}, + {"c", []string{}}, + {"*", []string{"a", "b", "dir"}}, + {"d*", []string{"dir"}}, + {"*i*", []string{"dir"}}, + {"*r", []string{"dir"}}, + {"?ir", []string{"dir"}}, + {"?r", []string{}}, + {"d*/*/bin/git.exe", []string{"dir/d/bin/git.exe"}}, + } + + // test absolute paths + for _, test := range tests { + var p string + err = test.globAbs(tmpDir, tmpDir) + if err != nil { + t.Error(err) + } + // test C:\*Documents and Settings\... + p = tmpDir + p = strings.Replace(p, `:\`, `:\*`, 1) + err = test.globAbs(tmpDir, p) + if err != nil { + t.Error(err) + } + // test C:\Documents and Settings*\... + p = tmpDir + p = strings.Replace(p, `:\`, `:`, 1) + p = strings.Replace(p, `\`, `*\`, 1) + p = strings.Replace(p, `:`, `:\`, 1) + err = test.globAbs(tmpDir, p) + if err != nil { + t.Error(err) + } + } + + // test relative paths + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + err = os.Chdir(tmpDir) + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.Chdir(wd) + if err != nil { + t.Fatal(err) + } + }() + for _, test := range tests { + err := test.globRel("") + if err != nil { + t.Error(err) + } + err = test.globRel(`.\`) + if err != nil { + t.Error(err) + } + err = test.globRel(tmpDir[:2]) // C: + if err != nil { + t.Error(err) + } + } +} From b6dc3e6f668e4e0a2d2f710a7604d163d8ca45e1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 01:33:24 -0400 Subject: [PATCH 250/267] cmd/compile: fix liveness computation for heap-escaped parameters The liveness computation of parameters generally was never correct, but forcing all parameters to be live throughout the function covered up that problem. The new SSA back end is too clever: even though it currently keeps the parameter values live throughout the function, it may find optimizations that mean the current values are not written back to the original parameter stack slots immediately or ever (for example if a parameter is set to nil, SSA constant propagation may replace all later uses of the parameter with a constant nil, eliminating the need to write the nil value back to the stack slot), so the liveness code must now track the actual operations on the stack slots, exposing these problems. One small problem in the handling of arguments is that nodarg can return ONAME PPARAM nodes with adjusted offsets, so that there are actually multiple *Node pointers for the same parameter in the instruction stream. This might be possible to correct, but not in this CL. For now, we fix this by using n.Orig instead of n when considering PPARAM and PPARAMOUT nodes. The major problem in the handling of arguments is general confusion in the liveness code about the meaning of PPARAM|PHEAP and PPARAMOUT|PHEAP nodes, especially as contrasted with PAUTO|PHEAP. The difference between these two is that when a local variable "moves" to the heap, it's really just allocated there to start with; in contrast, when an argument moves to the heap, the actual data has to be copied there from the stack at the beginning of the function, and when a result "moves" to the heap the value in the heap has to be copied back to the stack when the function returns This general confusion is also present in the SSA back end. The PHEAP bit worked decently when I first introduced it 7 years ago (!) in 391425ae. The back end did nothing sophisticated, and in particular there was no analysis at all: no escape analysis, no liveness analysis, and certainly no SSA back end. But the complications caused in the various downstream consumers suggest that this should be a detail kept mainly in the front end. This CL therefore eliminates both the PHEAP bit and even the idea of "heap variables" from the back ends. First, it replaces the PPARAM|PHEAP, PPARAMOUT|PHEAP, and PAUTO|PHEAP variable classes with the single PAUTOHEAP, a pseudo-class indicating a variable maintained on the heap and available by indirecting a local variable kept on the stack (a plain PAUTO). Second, walkexpr replaces all references to PAUTOHEAP variables with indirections of the corresponding PAUTO variable. The back ends and the liveness code now just see plain indirected variables. This may actually produce better code, but the real goal here is to eliminate these little-used and somewhat suspect code paths in the back end analyses. The OPARAM node type goes away too. A followup CL will do the same to PPARAMREF. I'm not sure that the back ends (SSA in particular) are handling those right either, and with the framework established in this CL that change is trivial and the result clearly more correct. Fixes #15747. Change-Id: I2770b1ce3cbc93981bfc7166be66a9da12013d74 Reviewed-on: https://go-review.googlesource.com/23393 Reviewed-by: Keith Randall Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/amd64/gsubr.go | 4 +- src/cmd/compile/internal/gc/align.go | 13 +- src/cmd/compile/internal/gc/bexport.go | 4 +- src/cmd/compile/internal/gc/cgen.go | 6 +- src/cmd/compile/internal/gc/cplx.go | 2 +- src/cmd/compile/internal/gc/esc.go | 7 +- src/cmd/compile/internal/gc/export.go | 2 +- src/cmd/compile/internal/gc/fmt.go | 15 +- src/cmd/compile/internal/gc/gen.go | 193 ++++++++++++++++------- src/cmd/compile/internal/gc/go.go | 3 +- src/cmd/compile/internal/gc/gsubr.go | 13 -- src/cmd/compile/internal/gc/inl.go | 18 +-- src/cmd/compile/internal/gc/opnames.go | 1 - src/cmd/compile/internal/gc/plive.go | 41 +++-- src/cmd/compile/internal/gc/racewalk.go | 3 +- src/cmd/compile/internal/gc/sinit.go | 2 +- src/cmd/compile/internal/gc/ssa.go | 58 ++----- src/cmd/compile/internal/gc/subr.go | 3 +- src/cmd/compile/internal/gc/syntax.go | 14 +- src/cmd/compile/internal/gc/typecheck.go | 2 +- src/cmd/compile/internal/gc/walk.go | 87 +++++----- src/cmd/compile/internal/x86/gsubr.go | 2 +- test/fixedbugs/issue15747.go | 41 +++++ test/fixedbugs/issue15747b.go | 19 +++ 24 files changed, 332 insertions(+), 221 deletions(-) create mode 100644 test/fixedbugs/issue15747.go create mode 100644 test/fixedbugs/issue15747b.go diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go index f862e8a92ba9bb..5d9070ca130c0d 100644 --- a/src/cmd/compile/internal/amd64/gsubr.go +++ b/src/cmd/compile/internal/amd64/gsubr.go @@ -116,7 +116,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { base = n1.Left } - if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG { + if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG { r1 = *n1 } else { gc.Regalloc(&r1, t, n1) @@ -229,6 +229,8 @@ func gmove(f *gc.Node, t *gc.Node) { switch uint32(ft)<<16 | uint32(tt) { default: + gc.Dump("f", f) + gc.Dump("t", t) gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong)) /* diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index 81230413182f4c..2b62405544d697 100644 --- a/src/cmd/compile/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -55,12 +55,15 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { } f.Offset = o if f.Nname != nil { - // this same stackparam logic is in addrescapes - // in typecheck.go. usually addrescapes runs after - // widstruct, in which case we could drop this, + // addrescapes has similar code to update these offsets. + // Usually addrescapes runs after widstruct, + // in which case we could drop this, // but function closure functions are the exception. - if f.Nname.Name.Param.Stackparam != nil { - f.Nname.Name.Param.Stackparam.Xoffset = o + // NOTE(rsc): This comment may be stale. + // It's possible the ordering has changed and this is + // now the common case. I'm not sure. + if f.Nname.Name.Param.Stackcopy != nil { + f.Nname.Name.Param.Stackcopy.Xoffset = o f.Nname.Xoffset = 0 } else { f.Nname.Xoffset = o diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 80b8e4f9450df3..f533053cd74acc 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1408,8 +1408,8 @@ func (p *exporter) stmt(n *Node) { switch op := n.Op; op { case ODCL: p.op(ODCL) - switch n.Left.Class &^ PHEAP { - case PPARAM, PPARAMOUT, PAUTO: + switch n.Left.Class { + case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP: // TODO(gri) when is this not PAUTO? // Also, originally this didn't look like // the default case. Investigate. diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go index fd57fbd4a7958b..c01a8fbda7efc8 100644 --- a/src/cmd/compile/internal/gc/cgen.go +++ b/src/cmd/compile/internal/gc/cgen.go @@ -519,7 +519,7 @@ func cgen_wb(n, res *Node, wb bool) { ODOTPTR, OINDEX, OIND, - ONAME: // PHEAP or PPARAMREF var + ONAME: // PPARAMREF var var n1 Node Igen(n, &n1, res) @@ -1579,7 +1579,7 @@ func Agen(n *Node, res *Node) { } // should only get here for heap vars or paramref - if n.Class&PHEAP == 0 && n.Class != PPARAMREF { + if n.Class != PPARAMREF { Dump("bad agen", n) Fatalf("agen: bad ONAME class %#x", n.Class) } @@ -1646,7 +1646,7 @@ func Igen(n *Node, a *Node, res *Node) { switch n.Op { case ONAME: - if (n.Class&PHEAP != 0) || n.Class == PPARAMREF { + if n.Class == PPARAMREF { break } *a = *n diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go index 9bb202752064f2..a5c04b2be52325 100644 --- a/src/cmd/compile/internal/gc/cplx.go +++ b/src/cmd/compile/internal/gc/cplx.go @@ -405,7 +405,7 @@ func Complexgen(n *Node, res *Node) { ODOTPTR, OINDEX, OIND, - ONAME, // PHEAP or PPARAMREF var + ONAME, // PPARAMREF var OCALLFUNC, OCALLMETH, OCALLINTER: diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 553dde8bf99cb9..2991f6d2256aea 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -1068,7 +1068,6 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) { OIND, // dst = *x ODOTPTR, // dst = (*x).f ONAME, - OPARAM, ODDDARG, OPTRLIT, OARRAYLIT, @@ -1835,20 +1834,20 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep, } if leaks { src.Esc = EscHeap - addrescapes(src.Left) if Debug['m'] != 0 && osrcesc != src.Esc { p := src if p.Left.Op == OCLOSURE { p = p.Left // merely to satisfy error messages in tests } if Debug['m'] > 2 { - Warnl(src.Lineno, "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v", - Nconv(p, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth) + Warnl(src.Lineno, "%v escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v", + Nconv(p, FmtShort), level, dst, dstE.Escloopdepth, modSrcLoopdepth) } else { Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort)) step.describe(src) } } + addrescapes(src.Left) escwalkBody(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth) extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op } else { diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 2dd137ed773c44..1148b27f025f17 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -121,7 +121,7 @@ func reexportdep(n *Node) { //print("reexportdep %+hN\n", n); switch n.Op { case ONAME: - switch n.Class &^ PHEAP { + switch n.Class { // methods will be printed along with their type // nodes for T.Method expressions case PFUNC: diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 82b84b3aa52f28..3c4053e51f7e73 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -218,6 +218,7 @@ var classnames = []string{ "Pxxx", "PEXTERN", "PAUTO", + "PAUTOHEAP", "PPARAM", "PPARAMOUT", "PPARAMREF", @@ -251,14 +252,10 @@ func jconv(n *Node, flag FmtFlag) string { } if n.Class != 0 { - s := "" - if n.Class&PHEAP != 0 { - s = ",heap" - } - if int(n.Class&^PHEAP) < len(classnames) { - fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s) + if int(n.Class) < len(classnames) { + fmt.Fprintf(&buf, " class(%s)", classnames[n.Class]) } else { - fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s) + fmt.Fprintf(&buf, " class(%d?)", n.Class) } } @@ -798,8 +795,8 @@ func stmtfmt(n *Node) string { switch n.Op { case ODCL: if fmtmode == FExp { - switch n.Left.Class &^ PHEAP { - case PPARAM, PPARAMOUT, PAUTO: + switch n.Left.Class { + case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP: f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type) goto ret } diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 275e6a750713a7..2db253184ca61d 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -43,52 +43,39 @@ func addrescapes(n *Node) { break } - switch n.Class { - case PPARAMREF: + // A PPARAMREF is a closure reference. + // Mark the thing it refers to as escaping. + if n.Class == PPARAMREF { addrescapes(n.Name.Defn) + break + } - // if func param, need separate temporary - // to hold heap pointer. - // the function type has already been checked - // (we're in the function body) - // so the param already has a valid xoffset. - - // expression to refer to stack copy - case PPARAM, PPARAMOUT: - n.Name.Param.Stackparam = Nod(OPARAM, n, nil) - - n.Name.Param.Stackparam.Type = n.Type - n.Name.Param.Stackparam.Addable = true - if n.Xoffset == BADWIDTH { - Fatalf("addrescapes before param assignment") - } - n.Name.Param.Stackparam.Xoffset = n.Xoffset - fallthrough - - case PAUTO: - n.Class |= PHEAP - - n.Addable = false - n.Ullman = 2 - n.Xoffset = 0 - - // create stack variable to hold pointer to heap - oldfn := Curfn + if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO { + break + } - 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) - n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym - n.Esc = EscHeap - if Debug['m'] != 0 { - fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) - } - Curfn = oldfn + // This is a plain parameter or local variable that needs to move to the heap, + // but possibly for the function outside the one we're compiling. + // That is, if we have: + // + // func f(x int) { + // func() { + // global = &x + // } + // } + // + // then we're analyzing the inner closure but we need to move x to the + // heap in f, not in the inner closure. Flip over to f before calling moveToHeap. + oldfn := Curfn + Curfn = n.Name.Curfn + if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE { + Curfn = Curfn.Func.Closure } + ln := lineno + lineno = Curfn.Lineno + moveToHeap(n) + Curfn = oldfn + lineno = ln case OIND, ODOTPTR: break @@ -105,6 +92,110 @@ func addrescapes(n *Node) { } } +// isParamStackCopy reports whether this is the on-stack copy of a +// function parameter that moved to the heap. +func (n *Node) isParamStackCopy() bool { + return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Heapaddr != nil +} + +// isParamHeapCopy reports whether this is the on-heap copy of +// a function parameter that moved to the heap. +func (n *Node) isParamHeapCopy() bool { + return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil +} + +// paramClass reports the parameter class (PPARAM or PPARAMOUT) +// of the node, which may be an unmoved on-stack parameter +// or the on-heap or on-stack copy of a parameter that moved to the heap. +// If the node is not a parameter, paramClass returns Pxxx. +func (n *Node) paramClass() Class { + if n.Op != ONAME { + return Pxxx + } + if n.Class == PPARAM || n.Class == PPARAMOUT { + return n.Class + } + if n.isParamHeapCopy() { + return n.Name.Param.Stackcopy.Class + } + return Pxxx +} + +// moveToHeap records the parameter or local variable n as moved to the heap. +func moveToHeap(n *Node) { + if Debug['r'] != 0 { + Dump("MOVE", n) + } + if compiling_runtime { + Yyerror("%v escapes to heap, not allowed in runtime.", n) + } + if n.Class == PAUTOHEAP { + Dump("n", n) + Fatalf("double move to heap") + } + + // Allocate a local stack variable to hold the pointer to the heap copy. + // temp will add it to the function declaration list automatically. + heapaddr := temp(Ptrto(n.Type)) + heapaddr.Sym = Lookup("&" + n.Sym.Name) + heapaddr.Orig.Sym = heapaddr.Sym + + // Parameters have a local stack copy used at function start/end + // in addition to the copy in the heap that may live longer than + // the function. + if n.Class == PPARAM || n.Class == PPARAMOUT { + if n.Xoffset == BADWIDTH { + Fatalf("addrescapes before param assignment") + } + + // We rewrite n below to be a heap variable (indirection of heapaddr). + // Preserve a copy so we can still write code referring to the original, + // and substitute that copy into the function declaration list + // so that analyses of the local (on-stack) variables use it. + stackcopy := Nod(ONAME, nil, nil) + stackcopy.Sym = n.Sym + stackcopy.Type = n.Type + stackcopy.Xoffset = n.Xoffset + stackcopy.Class = n.Class + stackcopy.Name.Heapaddr = heapaddr + if n.Class == PPARAM { + stackcopy.SetNotLiveAtEnd(true) + } + n.Name.Param.Stackcopy = stackcopy + + // Substitute the stackcopy into the function variable list so that + // liveness and other analyses use the underlying stack slot + // and not the now-pseudo-variable n. + found := false + for i, d := range Curfn.Func.Dcl { + if d == n { + Curfn.Func.Dcl[i] = stackcopy + found = true + break + } + // Parameters are before locals, so can stop early. + // This limits the search even in functions with many local variables. + if d.Class == PAUTO { + break + } + } + if !found { + Fatalf("cannot find %v in local variable list", n) + } + Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) + } + + // Modify n in place so that uses of n now mean indirection of the heapaddr. + n.Class = PAUTOHEAP + n.Ullman = 2 + n.Xoffset = 0 + n.Name.Heapaddr = heapaddr + n.Esc = EscHeap + if Debug['m'] != 0 { + fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) + } +} + func clearlabels() { for _, l := range labellist { l.Sym.Label = nil @@ -243,16 +334,9 @@ func cgen_dcl(n *Node) { Fatalf("cgen_dcl") } - if n.Class&PHEAP == 0 { - return + if n.Class == PAUTOHEAP { + Fatalf("cgen_dcl %v", n) } - if compiling_runtime { - Yyerror("%v escapes to heap, not allowed in runtime.", n) - } - if prealloc[n] == nil { - prealloc[n] = callnew(n.Type) - } - Cgen_as(n.Name.Heapaddr, prealloc[n]) } // generate discard of value @@ -263,7 +347,7 @@ func cgen_discard(nr *Node) { switch nr.Op { case ONAME: - if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF { + if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF { gused(nr) } @@ -908,11 +992,6 @@ func Cgen_as_wb(nl, nr *Node, wb bool) { } if nr == nil || iszero(nr) { - // heaps should already be clear - if nr == nil && (nl.Class&PHEAP != 0) { - return - } - tl := nl.Type if tl == nil { return diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index cbb79c02618a22..600b00dae2a56e 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -91,14 +91,13 @@ const ( Pxxx Class = iota PEXTERN // global variable PAUTO // local variables + PAUTOHEAP // local variable or parameter moved to heap PPARAM // input arguments PPARAMOUT // output results PPARAMREF // closure variable reference PFUNC // global function PDISCARD // discard during parse of duplicate import - - PHEAP = 1 << 7 // an extra bit to identify an escaped variable ) // note this is the runtime representation diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 603d0349d601b7..8f4da74150034d 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -53,7 +53,6 @@ func Ismem(n *Node) bool { OCAP, OINDREG, ONAME, - OPARAM, OCLOSUREVAR: return true @@ -349,18 +348,6 @@ func Naddr(a *obj.Addr, n *Node) { a.Width = 0 } - // n->left is PHEAP ONAME for stack parameter. - // compute address of actual parameter on stack. - case OPARAM: - a.Etype = uint8(Simtype[n.Left.Type.Etype]) - - a.Width = n.Left.Type.Width - a.Offset = n.Xoffset - a.Sym = Linksym(n.Left.Sym) - a.Type = obj.TYPE_MEM - a.Name = obj.NAME_PARAM - a.Node = n.Left.Orig - case OCLOSUREVAR: if !Curfn.Func.Needctxt { Fatalf("closurevar without needctxt") diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 95ba56edd2288c..0c1b05079c511f 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -27,9 +27,7 @@ package gc -import ( - "fmt" -) +import "fmt" // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods // the ->sym can be re-used in the local package, so peel it off the receiver's type. @@ -180,6 +178,7 @@ func ishairy(n *Node, budget *int32) bool { *budget -= fn.InlCost break } + if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 { *budget -= d.Func.InlCost @@ -568,14 +567,13 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { if ln.Class == PPARAMOUT { // return values handled below. continue } + if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap + continue + } if ln.Op == ONAME { - ln.Name.Inlvar = inlvar(ln) - - // Typecheck because inlvar is not necessarily a function parameter. - ln.Name.Inlvar = typecheck(ln.Name.Inlvar, Erv) - - if ln.Class&^PHEAP != PAUTO { - ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs + ln.Name.Inlvar = typecheck(inlvar(ln), Erv) + if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM { + ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil)) } } } diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go index 015baa2376a1b6..bcdae6c76272e4 100644 --- a/src/cmd/compile/internal/gc/opnames.go +++ b/src/cmd/compile/internal/gc/opnames.go @@ -76,7 +76,6 @@ var opnames = []string{ OINDEX: "INDEX", OINDEXMAP: "INDEXMAP", OKEY: "KEY", - OPARAM: "PARAM", OLEN: "LEN", OMAKE: "MAKE", OMAKECHAN: "MAKECHAN", diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index cf5359ecdf82ac..333cc9786a3b1f 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -203,6 +203,14 @@ func getvariables(fn *Node) []*Node { var result []*Node for _, ln := range fn.Func.Dcl { if ln.Op == ONAME { + switch ln.Class { + case PAUTO, PPARAM, PPARAMOUT, PFUNC, PAUTOHEAP: + // ok + default: + Dump("BAD NODE", ln) + Fatalf("getvariables") + } + // 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 @@ -567,7 +575,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini // read the out arguments - they won't be set until the new // function runs. for i, node := range vars { - switch node.Class &^ PHEAP { + switch node.Class { case PPARAM: if !node.NotLiveAtEnd() { bvset(uevar, int32(i)) @@ -595,7 +603,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini // A text instruction marks the entry point to a function and // the definition point of all in arguments. for i, node := range vars { - switch node.Class &^ PHEAP { + switch node.Class { case PPARAM: if node.Addrtaken { bvset(avarinit, int32(i)) @@ -610,23 +618,24 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 { from := &prog.From if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn { - switch ((from.Node).(*Node)).Class &^ PHEAP { + switch ((from.Node).(*Node)).Class { case PAUTO, PPARAM, PPARAMOUT: - pos, ok := from.Node.(*Node).Opt().(int32) // index in vars + n := from.Node.(*Node).Orig // orig needed for certain nodarg results + pos, ok := n.Opt().(int32) // index in vars if !ok { break } - if pos >= int32(len(vars)) || vars[pos] != from.Node { - Fatalf("bad bookkeeping in liveness %v %d", Nconv(from.Node.(*Node), 0), pos) + if pos >= int32(len(vars)) || vars[pos] != n { + Fatalf("bad bookkeeping in liveness %v %d", Nconv(n, 0), pos) } - if ((from.Node).(*Node)).Addrtaken { + if n.Addrtaken { bvset(avarinit, pos) } else { if prog.Info.Flags&(LeftRead|LeftAddr) != 0 { bvset(uevar, pos) } if prog.Info.Flags&LeftWrite != 0 { - if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) { + if !Isfat(n.Type) { bvset(varkill, pos) } } @@ -638,16 +647,17 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 { to := &prog.To if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn { - switch ((to.Node).(*Node)).Class &^ PHEAP { + switch ((to.Node).(*Node)).Class { case PAUTO, PPARAM, PPARAMOUT: - pos, ok := to.Node.(*Node).Opt().(int32) // index in vars + n := to.Node.(*Node).Orig // orig needed for certain nodarg results + pos, ok := n.Opt().(int32) // index in vars if !ok { return } - if pos >= int32(len(vars)) || vars[pos] != to.Node { - Fatalf("bad bookkeeping in liveness %v %d", Nconv(to.Node.(*Node), 0), pos) + if pos >= int32(len(vars)) || vars[pos] != n { + Fatalf("bad bookkeeping in liveness %v %d", Nconv(n, 0), pos) } - if ((to.Node).(*Node)).Addrtaken { + if n.Addrtaken { if prog.As != obj.AVARKILL { bvset(avarinit, pos) } @@ -667,7 +677,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini bvset(uevar, pos) } if prog.Info.Flags&RightWrite != 0 { - if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) { + if !Isfat(n.Type) || prog.As == obj.AVARDEF { bvset(varkill, pos) } } @@ -814,8 +824,7 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) { return } for _, a := range fn.Func.Dcl { - class := a.Class &^ PHEAP - if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n { + if a.Op == ONAME && (a.Class == PPARAM || a.Class == PPARAMOUT) && a == n { return } } diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 5bcaf89d50173a..3b705c3f0c9642 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -419,7 +419,6 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) { case OPRINT, // don't bother instrumenting it OPRINTN, // don't bother instrumenting it OCHECKNIL, // always followed by a read. - OPARAM, // it appears only in fn->exit to copy heap params back OCLOSUREVAR, // immutable pointer to captured variable ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT) OINDREG, // at this stage, only n(SP) nodes from nodarg @@ -496,7 +495,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool { // e.g. if we've got a local variable/method receiver // that has got a pointer inside. Whether it points to // the heap or not is impossible to know at compile time - if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { + if class == PAUTOHEAP || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { hascalls := 0 foreach(n, hascallspred, &hascalls) if hascalls != 0 { diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index c6f2acffbfcbb1..5d741a55db9d47 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -516,7 +516,7 @@ func isliteral(n *Node) bool { } func (n *Node) isSimpleName() bool { - return n.Op == ONAME && n.Addable && n.Class&PHEAP == 0 && n.Class != PPARAMREF + return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP && n.Class != PPARAMREF } func litas(l *Node, r *Node, init *Nodes) { diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 7bae8b46728ca4..8d06f1e3ed50ca 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -165,23 +165,15 @@ func buildssa(fn *Node) *ssa.Func { s.ptrargs = append(s.ptrargs, n) n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly } - case PAUTO | PHEAP: - // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition - aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n}) - s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) - case PPARAM | PHEAP, PPARAMOUT | PHEAP: - // This ends up wrong, have to do it at the PARAM node instead. case PAUTO: // processed at each use, to prevent Addr coming // before the decl. + case PAUTOHEAP: + // moved to heap - already handled by frontend case PFUNC: // local function - already handled by frontend default: - str := "" - if n.Class&PHEAP != 0 { - str = ",heap" - } - s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str) + s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class]) } } @@ -294,7 +286,7 @@ type state struct { // list of FwdRef values. fwdRefs []*ssa.Value - // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars. + // list of PPARAMOUT (return) variables. returns []*Node // list of PPARAM SSA-able pointer-shaped args. We ensure these are live @@ -593,25 +585,10 @@ func (s *state) stmt(n *Node) { return case ODCL: - if n.Left.Class&PHEAP == 0 { - return - } - if compiling_runtime { - Fatalf("%v escapes to heap, not allowed in runtime.", n) + if n.Left.Class == PAUTOHEAP { + Fatalf("DCL %v", n) } - // TODO: the old pass hides the details of PHEAP - // variables behind ONAME nodes. Figure out if it's better - // to rewrite the tree and make the heapaddr construct explicit - // or to keep this detail hidden behind the scenes. - palloc := prealloc[n.Left] - if palloc == nil { - palloc = callnew(n.Left.Type) - prealloc[n.Left] = palloc - } - r := s.expr(palloc) - s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0) - case OLABEL: sym := n.Left.Sym @@ -1451,9 +1428,6 @@ func (s *state) expr(n *Node) *ssa.Value { case OCFUNC: aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym}) return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb) - case OPARAM: - addr := s.addr(n, false) - return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem()) case ONAME: if n.Class == PFUNC { // "value" of a function is the address of the function's closure @@ -2749,10 +2723,10 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { // that cse works on their addresses aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n}) return s.newValue1A(ssa.OpAddr, t, aux, s.sp) - case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF: + case PPARAMREF: return s.expr(n.Name.Heapaddr) default: - s.Unimplementedf("variable address class %v not implemented", n.Class) + s.Unimplementedf("variable address class %v not implemented", classnames[n.Class]) return nil } case OINDREG: @@ -2795,17 +2769,6 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { case OCLOSUREVAR: return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))) - case OPARAM: - p := n.Left - if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) { - s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0)) - } - - // Recover original offset to address passed-in param value. - original_p := *p - original_p.Xoffset = n.Xoffset - aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p} - return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp) case OCONVNOP: addr := s.addr(n.Left, bounded) return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type @@ -2833,9 +2796,12 @@ func (s *state) canSSA(n *Node) bool { if n.Addrtaken { return false } - if n.Class&PHEAP != 0 { + if n.isParamHeapCopy() { return false } + if n.Class == PAUTOHEAP { + Fatalf("canSSA of PAUTOHEAP %v", n) + } switch n.Class { case PEXTERN, PPARAMREF: // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure? diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 6cfc610650a393..c78575a8c28da4 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1231,7 +1231,7 @@ func ullmancalc(n *Node) { switch n.Op { case OREGISTER, OLITERAL, ONAME: ul = 1 - if n.Class == PPARAMREF || (n.Class&PHEAP != 0) { + if n.Class == PPARAMREF || n.Class == PAUTOHEAP { ul++ } goto out @@ -2257,6 +2257,7 @@ func isbadimport(path string) bool { } func checknil(x *Node, init *Nodes) { + x = walkexpr(x, nil) // caller has not done this yet if x.Type.IsInterface() { x = Nod(OITAB, x, nil) x = typecheck(x, Erv) diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 0135061e684bbd..c5c7b17f5768cb 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -143,7 +143,7 @@ func (n *Node) SetOpt(x interface{}) { n.E = x } -// Name holds Node fields used only by named nodes (ONAME, OPACK, some OLITERAL). +// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, ODCLFIELD, some OLITERAL). type Name struct { Pack *Node // real package for import . names Pkg *Pkg // pkg for OPACK nodes @@ -151,7 +151,7 @@ type Name struct { Inlvar *Node // ONAME substitute while inlining Defn *Node // initializing assignment Curfn *Node // function for local variables - Param *Param + Param *Param // additional fields for ONAME, ODCLFIELD Decldepth int32 // declaration loop depth, increased for every loop or label Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one. Iota int32 // value if this name is iota @@ -167,16 +167,16 @@ type Name struct { type Param struct { Ntype *Node - // ONAME func param with PHEAP - Outerexpr *Node // expression copied into closure for variable - Stackparam *Node // OPARAM node referring to stack copy of param + // ONAME PAUTOHEAP + Outerexpr *Node // expression copied into closure for variable + Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only) // ONAME PPARAM Field *Field // TFIELD in arg struct // ONAME closure param with PPARAMREF Outer *Node // outer PPARAMREF in nested closure - Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF + Closure *Node // ONAME/PAUTOHEAP <-> ONAME/PPARAMREF } // Func holds Node fields used only with function-like nodes. @@ -292,7 +292,7 @@ const ( OINDEX // Left[Right] (index of array or slice) OINDEXMAP // Left[Right] (index of map) OKEY // Left:Right (key:value in struct/array/map literal, or slice index pair) - OPARAM // variant of ONAME for on-stack copy of a parameter or return value that escapes. + _ // was OPARAM, but cannot remove without breaking binary blob in builtin.go OLEN // len(Left) OMAKE // make(List) (before type checking converts to one of the following) OMAKECHAN // make(Type, Left) (type is chan) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index ffd4afcc01137e..bf4960a6daf088 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -3099,7 +3099,7 @@ func islvalue(n *Node) bool { return false } fallthrough - case OIND, ODOTPTR, OCLOSUREVAR, OPARAM: + case OIND, ODOTPTR, OCLOSUREVAR: return true case ODOT: diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 14784e284e93da..566decee45b68d 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -27,9 +27,8 @@ func walk(fn *Node) { lno := lineno // 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 i, ln := range fn.Func.Dcl { - if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO { + if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) { ln = typecheck(ln, Erv|Easgn) fn.Func.Dcl[i] = ln } @@ -37,13 +36,13 @@ func walk(fn *Node) { // Propagate the used flag for typeswitch variables up to the NONAME in it's definition. 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 { + if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used { ln.Name.Defn.Left.Used = true } } for _, ln := range fn.Func.Dcl { - if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used { + if ln.Op != ONAME || (ln.Class != PAUTO && ln.Class != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Used { continue } if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW { @@ -97,13 +96,13 @@ func samelist(a, b []*Node) bool { func paramoutheap(fn *Node) bool { for _, ln := range fn.Func.Dcl { switch ln.Class { - case PPARAMOUT, - PPARAMOUT | PHEAP: - return ln.Addrtaken + case PPARAMOUT: + if ln.isParamStackCopy() || ln.Addrtaken { + return true + } + case PAUTO: // stop early - parameters are over - case PAUTO, - PAUTO | PHEAP: return false } } @@ -212,7 +211,6 @@ func walkstmt(n *Node) *Node { n = addinit(n, init.Slice()) case OBREAK, - ODCL, OCONTINUE, OFALL, OGOTO, @@ -224,6 +222,21 @@ func walkstmt(n *Node) *Node { OVARLIVE: break + case ODCL: + v := n.Left + if v.Class == PAUTOHEAP { + if compiling_runtime { + Yyerror("%v escapes to heap, not allowed in runtime.", v) + } + if prealloc[v] == nil { + prealloc[v] = callnew(v.Type) + } + nn := Nod(OAS, v.Name.Heapaddr, prealloc[v]) + nn.Colas = true + nn = typecheck(nn, Etop) + return walkstmt(nn) + } + case OBLOCK: walkstmtlist(n.List.Slice()) @@ -295,11 +308,14 @@ func walkstmt(n *Node) *Node { var cl Class for _, ln := range Curfn.Func.Dcl { - cl = ln.Class &^ PHEAP - if cl == PAUTO { + cl = ln.Class + if cl == PAUTO || cl == PAUTOHEAP { break } if cl == PPARAMOUT { + if ln.isParamStackCopy() { + ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil) + } rl = append(rl, ln) } } @@ -487,6 +503,12 @@ func walkexpr(n *Node, init *Nodes) *Node { Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign)) } + if n.Op == ONAME && n.Class == PAUTOHEAP { + nn := Nod(OIND, n.Name.Heapaddr, nil) + nn = typecheck(nn, Erv) + return walkexpr(nn, init) + } + opswitch: switch n.Op { default: @@ -497,7 +519,6 @@ opswitch: ONONAME, OINDREG, OEMPTY, - OPARAM, OGETG: case ONOT, @@ -626,7 +647,7 @@ opswitch: n.Addable = true case ONAME: - if n.Class&PHEAP == 0 && n.Class != PPARAMREF { + if n.Class != PPARAMREF { n.Addable = true } @@ -1640,7 +1661,7 @@ func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node { break } // Do not generate 'x = x' during return. See issue 4014. - if op == ORETURN && nl[i] == nr[i] { + if op == ORETURN && samesafeexpr(nl[i], nr[i]) { continue } nn = append(nn, ascompatee1(op, nl[i], nr[i], init)) @@ -2553,11 +2574,6 @@ func vmatch1(l *Node, r *Node) bool { func paramstoheap(params *Type, out bool) []*Node { var nn []*Node for _, t := range params.Fields().Slice() { - v := t.Nname - if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result - v = nil - } - // For precise stacks, the garbage collector assumes results // are always live, so zero them always. if out { @@ -2567,24 +2583,19 @@ func paramstoheap(params *Type, out bool) []*Node { nn = append(nn, Nod(OAS, nodarg(t, -1), nil)) } - if v == nil || v.Class&PHEAP == 0 { + v := t.Nname + if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result + v = nil + } + if v == nil { continue } - // generate allocation & copying code - if compiling_runtime { - Yyerror("%v escapes to heap, not allowed in runtime.", v) - } - if prealloc[v] == nil { - prealloc[v] = callnew(v.Type) - } - 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 - as = typecheck(as, Etop) - as = applywritebarrier(as) - nn = append(nn, as) + if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil { + nn = append(nn, walkstmt(Nod(ODCL, v, nil))) + if stackcopy.Class == PPARAM { + nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop))) + } } } @@ -2597,10 +2608,12 @@ func returnsfromheap(params *Type) []*Node { var nn []*Node for _, t := range params.Fields().Slice() { v := t.Nname - if v == nil || v.Class != PHEAP|PPARAMOUT { + if v == nil { continue } - nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v)) + if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT { + nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop))) + } } return nn diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go index f432cd8933f93d..d91bafc4ea539f 100644 --- a/src/cmd/compile/internal/x86/gsubr.go +++ b/src/cmd/compile/internal/x86/gsubr.go @@ -643,7 +643,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { base = n1.Left } - if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG { + if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG { r1 = *n1 } else { gc.Regalloc(&r1, t, n1) diff --git a/test/fixedbugs/issue15747.go b/test/fixedbugs/issue15747.go new file mode 100644 index 00000000000000..34ec719f1281e2 --- /dev/null +++ b/test/fixedbugs/issue15747.go @@ -0,0 +1,41 @@ +// errorcheck -0 -live + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 15747: liveness analysis was marking heap-escaped params live too much, +// and worse was using the wrong bitmap bits to do so. + +package p + +var global *[]byte + +type Q struct{} + +type T struct{ M string } + +var b bool + +func f1(q *Q, xx []byte) interface{} { // ERROR "live at entry to f1: q xx" "live at call to newobject: q xx" "live at call to writebarrierptr: q &xx" + // xx was copied from the stack to the heap on the previous line: + // xx was live for the first two prints but then it switched to &xx + // being live. We should not see plain xx again. + if b { + global = &xx // ERROR "live at call to writebarrierptr: q &xx$" + } + xx, _, err := f2(xx, 5) // ERROR "live at call to newobject: q( d)? &xx( odata.ptr)?" "live at call to writebarrierptr: q (e|err.data err.type)$" + if err != nil { + return err + } + return nil +} + +func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d" + if n > len(d) { + return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d" + } + res = d[:n] + odata = d[n:] + return +} diff --git a/test/fixedbugs/issue15747b.go b/test/fixedbugs/issue15747b.go new file mode 100644 index 00000000000000..9620d3d0cb21a8 --- /dev/null +++ b/test/fixedbugs/issue15747b.go @@ -0,0 +1,19 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 15747: If a ODCL is dropped, for example when inlining, +// then it's easy to end up not initializing the '&x' pseudo-variable +// to point to an actual allocation. The liveness analysis will detect +// this and abort the computation, so this test just checks that the +// compilation succeeds. + +package p + +type R [100]byte + +func (x R) New() *R { + return &x +} From 20803b845f26111eb9281f8ece98383d48ea1b3f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 10:29:50 -0400 Subject: [PATCH 251/267] cmd/compile: eliminate PPARAMREF As in the elimination of PHEAP|PPARAM in CL 23393, this is something the front end can trivially take care of and then not bother the back ends with. It also eliminates some suspect (and only lightly exercised) code paths in the back ends. I don't have a smoking gun for this one but it seems more clearly correct. Change-Id: I3b3f5e669b3b81d091ff1e2fb13226a6f14c69d5 Reviewed-on: https://go-review.googlesource.com/23431 Reviewed-by: Keith Randall Run-TryBot: Russ Cox --- src/cmd/compile/internal/arm/gsubr.go | 11 +------- src/cmd/compile/internal/gc/cgen.go | 35 +++++++------------------ src/cmd/compile/internal/gc/closure.go | 2 +- src/cmd/compile/internal/gc/cplx.go | 1 - src/cmd/compile/internal/gc/dcl.go | 3 ++- src/cmd/compile/internal/gc/esc.go | 4 +-- src/cmd/compile/internal/gc/fmt.go | 1 - src/cmd/compile/internal/gc/gen.go | 7 +++-- src/cmd/compile/internal/gc/go.go | 1 - src/cmd/compile/internal/gc/racewalk.go | 2 +- src/cmd/compile/internal/gc/sinit.go | 2 +- src/cmd/compile/internal/gc/ssa.go | 5 +--- src/cmd/compile/internal/gc/subr.go | 2 +- src/cmd/compile/internal/gc/syntax.go | 17 +++++++++--- src/cmd/compile/internal/gc/walk.go | 6 ++--- src/cmd/compile/internal/x86/gsubr.go | 11 +------- 16 files changed, 39 insertions(+), 71 deletions(-) diff --git a/src/cmd/compile/internal/arm/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go index 9ac999167e1dbb..b5d7bc05c405e4 100644 --- a/src/cmd/compile/internal/arm/gsubr.go +++ b/src/cmd/compile/internal/arm/gsubr.go @@ -86,17 +86,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { n = &n1 - case gc.ONAME: - if n.Class == gc.PPARAMREF { - var n1 gc.Node - gc.Cgen(n.Name.Heapaddr, &n1) - sclean[nsclean-1] = n1 - n = &n1 - } - + case gc.ONAME, gc.OINDREG: // nothing - case gc.OINDREG: - break } *lo = *n diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go index c01a8fbda7efc8..dbefcc7a0bb52d 100644 --- a/src/cmd/compile/internal/gc/cgen.go +++ b/src/cmd/compile/internal/gc/cgen.go @@ -518,8 +518,7 @@ func cgen_wb(n, res *Node, wb bool) { case ODOT, ODOTPTR, OINDEX, - OIND, - ONAME: // PPARAMREF var + OIND: var n1 Node Igen(n, &n1, res) @@ -1545,6 +1544,7 @@ func Agen(n *Node, res *Node) { switch n.Op { default: + Dump("bad agen", n) Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign)) case OCALLMETH: @@ -1571,24 +1571,6 @@ func Agen(n *Node, res *Node) { Thearch.Gmove(&n1, res) Regfree(&n1) - case ONAME: - // should only get here with names in this func. - if n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth { - Dump("bad agen", n) - Fatalf("agen: bad ONAME funcdepth %d != %d", n.Name.Funcdepth, Funcdepth) - } - - // should only get here for heap vars or paramref - if n.Class != PPARAMREF { - Dump("bad agen", n) - Fatalf("agen: bad ONAME class %#x", n.Class) - } - - Cgen(n.Name.Heapaddr, res) - if n.Xoffset != 0 { - addOffset(res, n.Xoffset) - } - case OIND: Cgen(nl, res) if !nl.NonNil { @@ -1646,8 +1628,9 @@ func Igen(n *Node, a *Node, res *Node) { switch n.Op { case ONAME: - if n.Class == PPARAMREF { - break + if n.Class == PAUTOHEAP { + Dump("igen", n) + Fatalf("bad name") } *a = *n return @@ -1702,11 +1685,11 @@ func Igen(n *Node, a *Node, res *Node) { a.Type = n.Type return - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. case OINDEX: + // Index of fixed-size array by constant can + // put the offset in the addressing. + // Could do the same for slice except that we need + // to use the real index for the bounds checking. if n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) { if Isconst(n.Right, CTINT) { // Compute &a. diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 04fa2509858518..238280f68adb75 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -313,7 +313,7 @@ func transformclosure(xfunc *Node) { } else { // If v of type T is captured by reference, // we introduce function param &v *T - // and v remains PPARAMREF with &v heapaddr + // and v remains PAUTOHEAP with &v heapaddr // (accesses will implicitly deref &v). addr := newname(Lookupf("&%s", v.Sym.Name)) addr.Type = Ptrto(v.Type) diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go index a5c04b2be52325..96a1dfb3c26abf 100644 --- a/src/cmd/compile/internal/gc/cplx.go +++ b/src/cmd/compile/internal/gc/cplx.go @@ -405,7 +405,6 @@ func Complexgen(n *Node, res *Node) { ODOTPTR, OINDEX, OIND, - ONAME, // PPARAMREF var OCALLFUNC, OCALLMETH, OCALLINTER: diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index ba5b6b689cab01..3b1822ffd97e33 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -396,7 +396,8 @@ func oldname(s *Sym) *Node { c := Nod(ONAME, nil, nil) c.Sym = s - c.Class = PPARAMREF + c.Class = PAUTOHEAP + c.setIsClosureParam(true) c.Isddd = n.Isddd c.Name.Defn = n c.Addable = false diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 2991f6d2256aea..538c4842d90e81 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -1817,9 +1817,9 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep, } } - // Treat a PPARAMREF closure variable as equivalent to the + // Treat a captured closure variable as equivalent to the // original variable. - if src.Class == PPARAMREF { + if src.isClosureParam() { if leaks && Debug['m'] != 0 { Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort)) step.describe(src) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 3c4053e51f7e73..02d93e2e470e3a 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -221,7 +221,6 @@ var classnames = []string{ "PAUTOHEAP", "PPARAM", "PPARAMOUT", - "PPARAMREF", "PFUNC", } diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 2db253184ca61d..ec4a3c8142af72 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -43,9 +43,8 @@ func addrescapes(n *Node) { break } - // A PPARAMREF is a closure reference. - // Mark the thing it refers to as escaping. - if n.Class == PPARAMREF { + // If a closure reference escapes, mark the outer variable as escaping. + if n.isClosureParam() { addrescapes(n.Name.Defn) break } @@ -347,7 +346,7 @@ func cgen_discard(nr *Node) { switch nr.Op { case ONAME: - if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF { + if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC { gused(nr) } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 600b00dae2a56e..fedc785aeedb9f 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -94,7 +94,6 @@ const ( PAUTOHEAP // local variable or parameter moved to heap PPARAM // input arguments PPARAMOUT // output results - PPARAMREF // closure variable reference PFUNC // global function PDISCARD // discard during parse of duplicate import diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 3b705c3f0c9642..4a658b197665e9 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -495,7 +495,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool { // e.g. if we've got a local variable/method receiver // that has got a pointer inside. Whether it points to // the heap or not is impossible to know at compile time - if class == PAUTOHEAP || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { + if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { hascalls := 0 foreach(n, hascallspred, &hascalls) if hascalls != 0 { diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index 5d741a55db9d47..4469d71f1c56cc 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -516,7 +516,7 @@ func isliteral(n *Node) bool { } func (n *Node) isSimpleName() bool { - return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP && n.Class != PPARAMREF + return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP } func litas(l *Node, r *Node, init *Nodes) { diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 8d06f1e3ed50ca..a107f91ef3e70a 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -2723,8 +2723,6 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { // that cse works on their addresses aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n}) return s.newValue1A(ssa.OpAddr, t, aux, s.sp) - case PPARAMREF: - return s.expr(n.Name.Heapaddr) default: s.Unimplementedf("variable address class %v not implemented", classnames[n.Class]) return nil @@ -2803,8 +2801,7 @@ func (s *state) canSSA(n *Node) bool { Fatalf("canSSA of PAUTOHEAP %v", n) } switch n.Class { - case PEXTERN, PPARAMREF: - // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure? + case PEXTERN: return false case PPARAMOUT: if hasdefer { diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index c78575a8c28da4..c2abff7b63487b 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1231,7 +1231,7 @@ func ullmancalc(n *Node) { switch n.Op { case OREGISTER, OLITERAL, ONAME: ul = 1 - if n.Class == PPARAMREF || n.Class == PAUTOHEAP { + if n.Class == PAUTOHEAP { ul++ } goto out diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index c5c7b17f5768cb..89c96cb2d8b9ab 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -78,6 +78,7 @@ type Node struct { const ( hasBreak = 1 << iota notLiveAtEnd + isClosureParam ) func (n *Node) HasBreak() bool { @@ -100,6 +101,16 @@ func (n *Node) SetNotLiveAtEnd(b bool) { n.flags &^= notLiveAtEnd } } +func (n *Node) isClosureParam() bool { + return n.flags&isClosureParam != 0 +} +func (n *Node) setIsClosureParam(b bool) { + if b { + n.flags |= isClosureParam + } else { + n.flags &^= isClosureParam + } +} // Val returns the Val for the node. func (n *Node) Val() Val { @@ -174,9 +185,9 @@ type Param struct { // ONAME PPARAM Field *Field // TFIELD in arg struct - // ONAME closure param with PPARAMREF - Outer *Node // outer PPARAMREF in nested closure - Closure *Node // ONAME/PAUTOHEAP <-> ONAME/PPARAMREF + // ONAME closure linkage + Outer *Node + Closure *Node } // Func holds Node fields used only with function-like nodes. diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 566decee45b68d..30fb170e500cf2 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -647,9 +647,7 @@ opswitch: n.Addable = true case ONAME: - if n.Class != PPARAMREF { - n.Addable = true - } + n.Addable = true case OCALLINTER: usemethod(n) @@ -2536,7 +2534,7 @@ func vmatch1(l *Node, r *Node) bool { switch l.Op { case ONAME: switch l.Class { - case PPARAM, PPARAMREF, PAUTO: + case PPARAM, PAUTO: break // assignment to non-stack variable diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go index d91bafc4ea539f..6406326b60e050 100644 --- a/src/cmd/compile/internal/x86/gsubr.go +++ b/src/cmd/compile/internal/x86/gsubr.go @@ -724,17 +724,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { n = &n1 - case gc.ONAME: - if n.Class == gc.PPARAMREF { - var n1 gc.Node - gc.Cgen(n.Name.Heapaddr, &n1) - sclean[nsclean-1] = n1 - n = &n1 - } - + case gc.ONAME, gc.OINDREG: // nothing - case gc.OINDREG: - break } *lo = *n From e9228dd9490c3d4827170abeb8c82e68c175ecf0 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Wed, 25 May 2016 23:22:11 -0700 Subject: [PATCH 252/267] cmd/go: fixup for parsing SCP-like addresses This is a fixup change for commit 5cd294480364eb166751838a3df8f58649c214e1 that added parsing of SCP-like addresses. To get the expected output from (*url.URL).String(), Path needs to be set, not RawPath. Add a test for this, since it has already regressed multiple times. Updates #11457. Change-Id: I806f5abbd3cf65e5bdcef01aab872caa8a5b8891 Reviewed-on: https://go-review.googlesource.com/23447 Run-TryBot: Andrew Gerrand TryBot-Result: Gobot Gobot Reviewed-by: Andrew Gerrand --- src/cmd/go/go_test.go | 32 ++++++++++++++++++++++++++++++-- src/cmd/go/vcs.go | 8 ++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 987021ecca97b0..50e6b500dab3d7 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1151,7 +1151,7 @@ func TestImportCommentConflict(t *testing.T) { tg.grepStderr("found import comments", "go build did not mention comment conflict") } -// cmd/go: custom import path checking should not apply to github.com/xxx/yyy. +// cmd/go: custom import path checking should not apply to Go packages without import comment. func TestIssue10952(t *testing.T) { testenv.MustHaveExternalNetwork(t) if _, err := exec.LookPath("git"); err != nil { @@ -1170,6 +1170,34 @@ func TestIssue10952(t *testing.T) { tg.run("get", "-d", "-u", importPath) } +// Test git clone URL that uses SCP-like syntax and custom import path checking. +func TestIssue11457(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + if _, err := exec.LookPath("git"); err != nil { + t.Skip("skipping because git binary not found") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + const importPath = "github.com/rsc/go-get-issue-11457" + tg.run("get", "-d", "-u", importPath) + repoDir := tg.path("src/" + importPath) + tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457") + + // At this time, custom import path checking compares remotes verbatim (rather than + // just the host and path, skipping scheme and user), so we expect go get -u to fail. + // However, the goal of this test is to verify that gitRemoteRepo correctly parsed + // the SCP-like syntax, and we expect it to appear in the error message. + tg.runFail("get", "-d", "-u", importPath) + want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457" + if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) { + t.Error("expected clone URL to appear in stderr") + } +} + func TestGetGitDefaultBranch(t *testing.T) { testenv.MustHaveExternalNetwork(t) if _, err := exec.LookPath("git"); err != nil { @@ -2814,7 +2842,7 @@ func TestBinaryOnlyPackages(t *testing.T) { tg.grepStderr("no buildable Go source files", "did not complain about missing sources") tg.tempFile("src/p1/missing.go", `//go:binary-only-package - + package p1 func G() `) diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 3b6e08f155b0e0..10b8cf8c49dcfa 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -171,10 +171,10 @@ func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error // Eg, "git@github.com:user/repo" becomes // "ssh://git@github.com/user/repo". repoURL = &url.URL{ - Scheme: "ssh", - User: url.User(m[1]), - Host: m[2], - RawPath: m[3], + Scheme: "ssh", + User: url.User(m[1]), + Host: m[2], + Path: m[3], } } else { repoURL, err = url.Parse(out) From dec1bae916fc75a6718fb7fa667e419cc902097a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 25 May 2016 10:01:58 -0400 Subject: [PATCH 253/267] cmd/compile: additional paranoia and checking in plive.go The main check here is that liveness now crashes if it finds an instruction using a variable that should be tracked but is not. Comments and adjustments in nodarg to explain what's going on and to remove the "-1" argument added a few months ago, plus a sketch of a future simplification. The need for n.Orig in the earlier CL seems to have been an intermediate problem rather than fundamental: the new explanations in nodarg make clear that nodarg is not causing the problem I thought, and in fact now using n instead of n.Orig works fine in plive.go. Change-Id: I3f5cf9f6e4438a6d27abac7d490e7521545cd552 Reviewed-on: https://go-review.googlesource.com/23450 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/closure.go | 2 +- src/cmd/compile/internal/gc/dcl.go | 12 +-- src/cmd/compile/internal/gc/fmt.go | 4 +- src/cmd/compile/internal/gc/gsubr.go | 81 ++++++++++++----- src/cmd/compile/internal/gc/plive.go | 115 ++++++++++-------------- src/cmd/compile/internal/gc/type.go | 18 +++- src/cmd/compile/internal/gc/universe.go | 6 +- src/cmd/compile/internal/gc/walk.go | 12 +-- 8 files changed, 139 insertions(+), 111 deletions(-) diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 238280f68adb75..29ee981ad91fd5 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -303,7 +303,7 @@ func transformclosure(xfunc *Node) { continue } fld := newField() - fld.Funarg = true + fld.Funarg = FunargParams if v.Name.Byval { // If v is captured by value, we merely downgrade it to PPARAM. v.Class = PPARAM diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 3b1822ffd97e33..b22b6cdde5f0b7 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -828,14 +828,14 @@ func tostruct0(t *Type, l []*Node) { } } -func tofunargs(l []*Node) *Type { +func tofunargs(l []*Node, funarg Funarg) *Type { t := typ(TSTRUCT) - t.StructType().Funarg = true + t.StructType().Funarg = funarg fields := make([]*Field, len(l)) for i, n := range l { f := structfield(n) - f.Funarg = true + f.Funarg = funarg // esc.go needs to find f given a PPARAM to add the tag. if n.Left != nil && n.Left.Class == PPARAM { @@ -1026,9 +1026,9 @@ func functype0(t *Type, this *Node, in, out []*Node) { if this != nil { rcvr = []*Node{this} } - *t.RecvsP() = tofunargs(rcvr) - *t.ResultsP() = tofunargs(out) - *t.ParamsP() = tofunargs(in) + *t.RecvsP() = tofunargs(rcvr, FunargRcvr) + *t.ResultsP() = tofunargs(out, FunargResults) + *t.ParamsP() = tofunargs(in, FunargParams) checkdupfields("argument", t.Recvs(), t.Results(), t.Params()) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 02d93e2e470e3a..ee88eedcf3efa2 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1659,7 +1659,7 @@ func Fldconv(f *Field, flag FmtFlag) string { } if s != nil && f.Embedded == 0 { - if f.Funarg { + if f.Funarg != FunargNone { name = Nconv(f.Nname, 0) } else if flag&FmtLong != 0 { name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg) @@ -1692,7 +1692,7 @@ func Fldconv(f *Field, flag FmtFlag) string { // (The escape analysis tags do not apply to func vars.) // But it must not suppress struct field tags. // See golang.org/issue/13777 and golang.org/issue/14331. - if flag&FmtShort == 0 && (!fmtbody || !f.Funarg) && f.Note != "" { + if flag&FmtShort == 0 && (!fmtbody || f.Funarg == FunargNone) && f.Note != "" { str += " " + strconv.Quote(f.Note) } diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 8f4da74150034d..4943d9dddeda49 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -515,25 +515,36 @@ func newplist() *obj.Plist { return pl } -// nodarg does something that depends on the value of -// fp (this was previously completely undocumented). +// nodarg returns a Node for the function argument denoted by t, +// which is either the entire function argument or result struct (t is a struct *Type) +// or a specific argument (t is a *Field within a struct *Type). // -// fp=1 corresponds to input args -// fp=0 corresponds to output args -// fp=-1 is a special case of output args for a -// specific call from walk that previously (and -// incorrectly) passed a 1; the behavior is exactly -// the same as it is for 1, except that PARAMOUT is -// generated instead of PARAM. +// If fp is 0, the node is for use by a caller invoking the given +// function, preparing the arguments before the call +// or retrieving the results after the call. +// In this case, the node will correspond to an outgoing argument +// slot like 8(SP). +// +// If fp is 1, the node is for use by the function itself +// (the callee), to retrieve its arguments or write its results. +// In this case the node will be an ONAME with an appropriate +// type and offset. func nodarg(t interface{}, fp int) *Node { var n *Node + var funarg Funarg switch t := t.(type) { + default: + Fatalf("bad nodarg %T(%v)", t, t) + case *Type: - // entire argument struct, not just one arg + // Entire argument struct, not just one arg if !t.IsFuncArgStruct() { Fatalf("nodarg: bad type %v", t) } + funarg = t.StructType().Funarg + + // Build fake variable name for whole arg struct. n = Nod(ONAME, nil, nil) n.Sym = Lookup(".args") n.Type = t @@ -546,15 +557,43 @@ func nodarg(t interface{}, fp int) *Node { } n.Xoffset = first.Offset n.Addable = true + case *Field: - if fp == 1 || fp == -1 { + funarg = t.Funarg + if fp == 1 { + // NOTE(rsc): This should be using t.Nname directly, + // except in the case where t.Nname.Sym is the blank symbol and + // so the assignment would be discarded during code generation. + // In that case we need to make a new node, and there is no harm + // in optimization passes to doing so. But otherwise we should + // definitely be using the actual declaration and not a newly built node. + // The extra Fatalf checks here are verifying that this is the case, + // without changing the actual logic (at time of writing, it's getting + // toward time for the Go 1.7 beta). + // At some quieter time (assuming we've never seen these Fatalfs happen) + // we could change this code to use "expect" directly. + expect := t.Nname + if expect.isParamHeapCopy() { + expect = expect.Name.Param.Stackcopy + } + for _, n := range Curfn.Func.Dcl { if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym { + if n != expect { + Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, t.Nname, t.Nname, t.Nname.Op) + } return n } } + + if !isblanksym(expect.Sym) { + Fatalf("nodarg: did not find node in dcl list: %v", expect) + } } + // Build fake name for individual variable. + // This is safe because if there was a real declared name + // we'd have used it above. n = Nod(ONAME, nil, nil) n.Type = t.Type n.Sym = t.Sym @@ -564,8 +603,6 @@ func nodarg(t interface{}, fp int) *Node { n.Xoffset = t.Offset n.Addable = true n.Orig = t.Nname - default: - panic("unreachable") } // Rewrite argument named _ to __, @@ -576,23 +613,23 @@ func nodarg(t interface{}, fp int) *Node { } switch fp { - case 0: // output arg - n.Op = OINDREG + default: + Fatalf("bad fp") + case 0: // preparing arguments for call + n.Op = OINDREG n.Reg = int16(Thearch.REGSP) n.Xoffset += Ctxt.FixedFrameSize() - case 1: // input arg + case 1: // reading arguments inside call n.Class = PPARAM - - case -1: // output arg from paramstoheap - n.Class = PPARAMOUT - - case 2: // offset output arg - Fatalf("shouldn't be used") + if funarg == FunargResults { + n.Class = PPARAMOUT + } } n.Typecheck = 1 + n.Addrtaken = true // keep optimizers at bay return n } diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 333cc9786a3b1f..85138c9fcde140 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -197,62 +197,41 @@ func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool { return false } -// Collects and returns a slice of *Nodes for functions arguments and local -// variables. -func getvariables(fn *Node) []*Node { - var result []*Node - for _, ln := range fn.Func.Dcl { - if ln.Op == ONAME { - switch ln.Class { - case PAUTO, PPARAM, PPARAMOUT, PFUNC, PAUTOHEAP: - // ok - default: - Dump("BAD NODE", ln) - Fatalf("getvariables") - } +// livenessShouldTrack reports whether the liveness analysis +// should track the variable n. +// We don't care about variables that have no pointers, +// nor do we care about non-local variables, +// nor do we care about empty structs (handled by the pointer check), +// nor do we care about the fake PAUTOHEAP variables. +func livenessShouldTrack(n *Node) bool { + return n.Op == ONAME && (n.Class == PAUTO || n.Class == PPARAM || n.Class == PPARAMOUT) && haspointers(n.Type) +} - // 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 - // bytes in the frame where variables containing pointers live. - // For arguments and results, the bitmap covers all variables, - // so we must include all the variables, even the ones without - // pointers. - // +// getvariables returns the list of on-stack variables that we need to track. +func getvariables(fn *Node) []*Node { + var vars []*Node + for _, n := range fn.Func.Dcl { + if n.Op == ONAME { // The Node.opt field is available for use by optimization passes. - // We use it to hold the index of the node in the variables array, plus 1 - // (so that 0 means the Node is not in the variables array). - // Each pass should clear opt when done, but you never know, - // so clear them all ourselves too. + // We use it to hold the index of the node in the variables array + // (nil means the Node is not in the variables array). // The Node.curfn field is supposed to be set to the current function // already, but for some compiler-introduced names it seems not to be, // so fix that here. // 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 + // we will check that n.Curfn == Curfn and n.Opt() != nil. Then n.Opt().(int32) // is the index in the variables list. - ln.SetOpt(nil) - - // The compiler doesn't emit initializations for zero-width parameters or results. - if ln.Type.Width == 0 { - continue - } - - ln.Name.Curfn = Curfn - switch ln.Class { - case PAUTO: - if haspointers(ln.Type) { - ln.SetOpt(int32(len(result))) - result = append(result, ln) - } + n.SetOpt(nil) + n.Name.Curfn = Curfn + } - case PPARAM, PPARAMOUT: - ln.SetOpt(int32(len(result))) - result = append(result, ln) - } + if livenessShouldTrack(n) { + n.SetOpt(int32(len(vars))) + vars = append(vars, n) } } - return result + return vars } // A pretty printer for control flow graphs. Takes a slice of *BasicBlocks. @@ -617,17 +596,9 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 { from := &prog.From - if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn { - switch ((from.Node).(*Node)).Class { - case PAUTO, PPARAM, PPARAMOUT: - n := from.Node.(*Node).Orig // orig needed for certain nodarg results - pos, ok := n.Opt().(int32) // index in vars - if !ok { - break - } - if pos >= int32(len(vars)) || vars[pos] != n { - Fatalf("bad bookkeeping in liveness %v %d", Nconv(n, 0), pos) - } + if from.Node != nil && from.Sym != nil { + n := from.Node.(*Node) + if pos := liveIndex(n, vars); pos >= 0 { if n.Addrtaken { bvset(avarinit, pos) } else { @@ -646,17 +617,9 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 { to := &prog.To - if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn { - switch ((to.Node).(*Node)).Class { - case PAUTO, PPARAM, PPARAMOUT: - n := to.Node.(*Node).Orig // orig needed for certain nodarg results - pos, ok := n.Opt().(int32) // index in vars - if !ok { - return - } - if pos >= int32(len(vars)) || vars[pos] != n { - Fatalf("bad bookkeeping in liveness %v %d", Nconv(n, 0), pos) - } + if to.Node != nil && to.Sym != nil { + n := to.Node.(*Node) + if pos := liveIndex(n, vars); pos >= 0 { if n.Addrtaken { if prog.As != obj.AVARKILL { bvset(avarinit, pos) @@ -687,6 +650,24 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini } } +// liveIndex returns the index of n in the set of tracked vars. +// If n is not a tracked var, liveIndex returns -1. +// If n is not a tracked var but should be tracked, liveIndex crashes. +func liveIndex(n *Node, vars []*Node) int32 { + if n.Name.Curfn != Curfn || !livenessShouldTrack(n) { + return -1 + } + + pos, ok := n.Opt().(int32) // index in vars + if !ok { + Fatalf("lost track of variable in liveness: %v (%p, %p)", n, n, n.Orig) + } + if pos >= int32(len(vars)) || vars[pos] != n { + Fatalf("bad bookkeeping in liveness: %v (%p, %p)", n, n, n.Orig) + } + return pos +} + // Constructs a new liveness structure used to hold the global state of the // liveness computation. The cfg argument is a slice of *BasicBlocks and the // vars argument is a slice of *Nodes. diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index 9ae05f7ff1f1a5..ab13df6eba5981 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -223,10 +223,20 @@ type StructType struct { // Map links such structs back to their map type. Map *Type - Funarg bool // whether this struct represents function parameters - Haspointers uint8 // 0 unknown, 1 no, 2 yes + Funarg Funarg // type of function arguments for arg struct + Haspointers uint8 // 0 unknown, 1 no, 2 yes } +// Fnstruct records the kind of function argument +type Funarg uint8 + +const ( + FunargNone Funarg = iota + FunargRcvr // receiver + FunargParams // input parameters + FunargResults // output results +) + // StructType returns t's extra struct-specific fields. func (t *Type) StructType() *StructType { t.wantEtype(TSTRUCT) @@ -287,7 +297,7 @@ type SliceType struct { type Field struct { Nointerface bool Embedded uint8 // embedded field - Funarg bool + Funarg Funarg Broke bool // broken field definition Isddd bool // field is ... argument @@ -786,7 +796,7 @@ func (t *Type) SetNname(n *Node) { // IsFuncArgStruct reports whether t is a struct representing function parameters. func (t *Type) IsFuncArgStruct() bool { - return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg + return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg != FunargNone } func (t *Type) Methods() *Fields { diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go index 84df22502fff93..b55af7e25a0a7b 100644 --- a/src/cmd/compile/internal/gc/universe.go +++ b/src/cmd/compile/internal/gc/universe.go @@ -362,16 +362,16 @@ func lexinit1() { // t = interface { Error() string } rcvr := typ(TSTRUCT) - rcvr.StructType().Funarg = true + rcvr.StructType().Funarg = FunargRcvr field := newField() field.Type = Ptrto(typ(TSTRUCT)) rcvr.SetFields([]*Field{field}) in := typ(TSTRUCT) - in.StructType().Funarg = true + in.StructType().Funarg = FunargParams out := typ(TSTRUCT) - out.StructType().Funarg = true + out.StructType().Funarg = FunargResults field = newField() field.Type = Types[TSTRING] out.SetFields([]*Field{field}) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 30fb170e500cf2..66eb7e97ac6c6d 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -2569,16 +2569,16 @@ func vmatch1(l *Node, r *Node) bool { // and to copy non-result prameters' values from the stack. // If out is true, then code is also produced to zero-initialize their // stack memory addresses. -func paramstoheap(params *Type, out bool) []*Node { +func paramstoheap(params *Type) []*Node { var nn []*Node for _, t := range params.Fields().Slice() { // For precise stacks, the garbage collector assumes results // are always live, so zero them always. - if out { + if params.StructType().Funarg == FunargResults { // 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 = append(nn, Nod(OAS, nodarg(t, -1), nil)) + nn = append(nn, Nod(OAS, nodarg(t, 1), nil)) } v := t.Nname @@ -2623,9 +2623,9 @@ func returnsfromheap(params *Type) []*Node { func heapmoves() { lno := lineno lineno = Curfn.Lineno - nn := paramstoheap(Curfn.Type.Recvs(), false) - nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...) - nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...) + nn := paramstoheap(Curfn.Type.Recvs()) + nn = append(nn, paramstoheap(Curfn.Type.Params())...) + nn = append(nn, paramstoheap(Curfn.Type.Results())...) Curfn.Func.Enter.Append(nn...) lineno = Curfn.Func.Endlineno Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...) From 65dd08197ece4f64b990aa0023286c8f6abc25fa Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Fri, 27 May 2016 02:31:59 -0600 Subject: [PATCH 254/267] doc/go1.7: document signal name printing during panics Document new behavior about signal name printing in panics as per CL golang.org/cl/22753. For #15810 Change-Id: I9c677d5dd779b41e82afa25e3c797d8e739600d3 Reviewed-on: https://go-review.googlesource.com/23493 Reviewed-by: Russ Cox --- doc/go1.7.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/go1.7.html b/doc/go1.7.html index db249dd0531124..a49ea833004ece 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -397,6 +397,11 @@

Runtime

required by the language specification.

+

+During panics, if a signal's name is known, it will be printed in the stack trace. +Otherwise, the signal's number will be used, as it was before Go1.7. +

+

The new function KeepAlive From cedc7c8f2091129514276c3c2f5f046f523a4684 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 27 May 2016 10:58:00 -0400 Subject: [PATCH 255/267] doc/go1.7.html: incorporate Rob's comments from CL 23379 For #15810. Change-Id: Ib529808f664392feb9b36770f3d3d875fcb54528 Reviewed-on: https://go-review.googlesource.com/23488 Run-TryBot: Russ Cox Reviewed-by: Rob Pike TryBot-Result: Gobot Gobot --- doc/go1.7.html | 58 ++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/doc/go1.7.html b/doc/go1.7.html index a49ea833004ece..7945622f6b8cad 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -26,10 +26,11 @@

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

@@ -48,12 +49,11 @@

Introduction to Go 1.7

updates the x86-64 compiler back end to generate more efficient code; includes the context package, promoted from the x/net subrepository -and now used throughout the standard library; +and now used in the standard library; and adds support in the testing package for creating hierarchies of tests and benchmarks. -The release also removes the ability to disable -the vendoring changes started in Go 1.5: -vendoring is now an official part of the Go toolchain. +The release also finalizes the vendoring support +started in Go 1.5, making it a standard feature.

Changes to the language

@@ -69,6 +69,7 @@

Changes to the language

The go/types package has been updated to match the gc and gccgo compiler toolchains in this respect. +This change has no effect on the correctness of existing programs.

Ports

@@ -86,7 +87,6 @@

Ports

The experimental port to Linux on big-endian 64-bit PowerPC (linux/ppc64) now requires the POWER8 architecture or later. -TODO: Pending ppc64le change for cgo.

@@ -138,7 +138,8 @@

Compiler Toolchain

generates more compact, more efficient code and provides a better platform for optimizations such as bounds check elimination. -The new back end reduces the CPU time required by our benchmark programs by 5-35%. +The new back end reduces the CPU time required by +our benchmark programs by 5-35%.

@@ -229,7 +230,7 @@

Go command

This release removes support for the GO15VENDOREXPERIMENT environment variable, as announced in the Go 1.6 release. Vendoring support -is now a standard feature of the go command and toolchain. +is now a standard feature of the go command and toolchain.

@@ -360,10 +361,6 @@

Context

as noted below.

-

-TODO: Example here. -

-

For more information about contexts, see the package documentation @@ -376,14 +373,10 @@

Testing

The testing package now supports the definition of tests with subtests and benchmarks with sub-benchmarks. -

- -

-TODO: Where is the documentation for this? -

- -

-TODO: Example here. +This support makes it easy to write table-driven benchmarks +and to create hierarchical tests. +It also provides a way to share common setup and tear-down code. +See the package documentation for details.

Runtime

@@ -406,7 +399,8 @@

Runtime

The new function KeepAlive provides an explicit mechanism for declaring -that an allocated object is currently reachable, +that an allocated object must be considered reachable +at a particular point in a program, typically to delay the execution of an associated finalizer.

@@ -533,14 +527,20 @@

Minor changes to the library

-TODO: Describe Config.DynamicRecordSizingDisabled or whatever replaces it. +The TLS implementation sends the first few data packets on each connection +using small record sizes, gradually increasing to the TLS maximum record size. +This heuristic reduces the amount of data that must be received before +the first packet can be decrypted, improving communication latency over +low-bandwidth networks. +Config's +DynamicRecordSizingDisabled field to true.

The TLS client now has optional, limited support for server-initiated renegotiation, enabled by setting the Config's -Renegotiation field. +Renegotiation field. This is needed for connecting to many Microsoft Azure servers.

@@ -815,8 +815,8 @@

Minor changes to the library

Transport implementation passes the request context to any dial operation connecting to the remote server. If a custom dialer is needed, the new Transport field -Dialer is preferred over the existing Dial field, -because the former can accept a context. +DialContext is preferred over the existing Dial field, +to allow the transport to supply a context.

@@ -1086,14 +1086,6 @@

Minor changes to the library

-
text/scanner
- -
-

-TODO: Describe whatever the final state is after golang.org/issue/15813 is resolved. -

-
-
time
From 93369001c76e01b2fe8b0d8a5074d62d0b8fdc81 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 26 May 2016 23:43:19 -0400 Subject: [PATCH 256/267] cmd/compile: delete Func.Outer This was just storage for a linked list. Change-Id: I850e8db1e1f5e72410f5c904be9409179b56a94a Reviewed-on: https://go-review.googlesource.com/23484 Reviewed-by: David Chase --- src/cmd/compile/internal/gc/dcl.go | 28 +++++++++++++--------- src/cmd/compile/internal/gc/go.go | 2 -- src/cmd/compile/internal/gc/sizeof_test.go | 2 +- src/cmd/compile/internal/gc/syntax.go | 3 +-- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index b22b6cdde5f0b7..12a217753ac31b 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -505,10 +505,8 @@ func ifacedcl(n *Node) { n.Func = new(Func) n.Func.FCurfn = Curfn dclcontext = PPARAM - markdcl() - Funcdepth++ - n.Func.Outer = Curfn - Curfn = n + + funcstart(n) funcargs(n.Right) // funcbody is normally called after the parser has @@ -535,11 +533,7 @@ func funchdr(n *Node) { } dclcontext = PAUTO - markdcl() - Funcdepth++ - - n.Func.Outer = Curfn - Curfn = n + funcstart(n) if n.Func.Nname != nil { funcargs(n.Func.Nname.Name.Param.Ntype) @@ -672,6 +666,19 @@ func funcargs2(t *Type) { } } +var funcstack []*Node // stack of previous values of Curfn +var Funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation + + +// start the function. +// called before funcargs; undone at end of funcbody. +func funcstart(n *Node) { + markdcl() + funcstack = append(funcstack, Curfn) + Funcdepth++ + Curfn = n +} + // finish the body. // called in auto-declaration context. // returns in extern-declaration context. @@ -681,9 +688,8 @@ func funcbody(n *Node) { Fatalf("funcbody: unexpected dclcontext %d", dclcontext) } popdcl() + funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1] Funcdepth-- - Curfn = n.Func.Outer - n.Func.Outer = nil if Funcdepth == 0 { dclcontext = PEXTERN } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index fedc785aeedb9f..b6b858c0d980c8 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -259,8 +259,6 @@ var Widthreg int var nblank *Node -var Funcdepth int32 - var typecheckok bool var compiling_runtime bool diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go index a01da13883e5a9..c474c47ddbdced 100644 --- a/src/cmd/compile/internal/gc/sizeof_test.go +++ b/src/cmd/compile/internal/gc/sizeof_test.go @@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) { _64bit uintptr // size on 64bit platforms }{ {Flow{}, 52, 88}, - {Func{}, 96, 168}, + {Func{}, 92, 160}, {Name{}, 52, 80}, {Node{}, 92, 144}, {Sym{}, 60, 112}, diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 89c96cb2d8b9ab..cd4f2e6d62d8b4 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -199,9 +199,8 @@ type Func struct { Dcl []*Node // autodcl for this func/closure Inldcl Nodes // copy of dcl for use in inlining Closgen int - Outerfunc *Node + Outerfunc *Node // outer function (for closure) FieldTrack map[*Sym]struct{} - Outer *Node // outer func for closure Ntype *Node // signature Top int // top context (Ecall, Eproc, etc) Closure *Node // OCLOSURE <-> ODCLFUNC From 36a80c5941ec36d9c44d6f3c068d13201e023b5f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 27 May 2016 00:56:19 -0400 Subject: [PATCH 257/267] cmd/compile: clean up, document Node closure fields Requested during CL 23431. Change-Id: I513ae42166b3a9fcfe51231ff55c163ab672e7d2 Reviewed-on: https://go-review.googlesource.com/23485 Reviewed-by: David Chase --- src/cmd/compile/internal/gc/closure.go | 49 ++++++++++--- src/cmd/compile/internal/gc/dcl.go | 23 +++--- src/cmd/compile/internal/gc/esc.go | 8 +-- src/cmd/compile/internal/gc/fmt.go | 2 +- src/cmd/compile/internal/gc/gen.go | 2 +- src/cmd/compile/internal/gc/syntax.go | 89 +++++++++++++++++++++--- src/cmd/compile/internal/gc/typecheck.go | 16 ++--- 7 files changed, 144 insertions(+), 45 deletions(-) diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 29ee981ad91fd5..6d84aed7b108f0 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -66,8 +66,39 @@ func closurebody(body []*Node) *Node { // unhook them. // make the list of pointers for the closure call. 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) + // Unlink from v1; see comment in syntax.go type Param for these fields. + v1 := v.Name.Defn + v1.Name.Param.Innermost = v.Name.Param.Outer + + // If the closure usage of v is not dense, + // we need to make it dense; now that we're out + // of the function in which v appeared, + // look up v.Sym in the enclosing function + // and keep it around for use in the compiled code. + // + // That is, suppose we just finished parsing the innermost + // closure f4 in this code: + // + // func f() { + // v := 1 + // func() { // f2 + // use(v) + // func() { // f3 + // func() { // f4 + // use(v) + // }() + // }() + // }() + // } + // + // At this point v.Outer is f2's v; there is no f3's v. + // To construct the closure f4 from within f3, + // we need to use f3's v and in this case we need to create f3's v. + // We are now in the context of f3, so calling oldname(v.Sym) + // obtains f3's v, creating it if necessary (as it is in the example). + // + // capturevars will decide whether to use v directly or &v. + v.Name.Param.Outer = oldname(v.Sym) } return func_ @@ -75,7 +106,7 @@ func closurebody(body []*Node) *Node { func typecheckclosure(func_ *Node, top int) { for _, ln := range func_.Func.Cvars.Slice() { - n := ln.Name.Param.Closure + n := ln.Name.Defn if !n.Name.Captured { n.Name.Captured = true if n.Name.Decldepth == 0 { @@ -215,8 +246,6 @@ 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 outer *Node - lno := lineno lineno = xfunc.Lineno @@ -239,14 +268,14 @@ func capturevars(xfunc *Node) { // so that the outer frame also grabs them and knows they escape. dowidth(v.Type) - outer = v.Name.Param.Outerexpr - v.Name.Param.Outerexpr = nil + outer := v.Name.Param.Outer + outermost := v.Name.Defn // out parameters will be assigned to implicitly upon return. - if outer.Class != PPARAMOUT && !v.Name.Param.Closure.Addrtaken && !v.Name.Param.Closure.Assigned && v.Type.Width <= 128 { + if outer.Class != PPARAMOUT && !outermost.Addrtaken && !outermost.Assigned && v.Type.Width <= 128 { v.Name.Byval = true } else { - v.Name.Param.Closure.Addrtaken = true + outermost.Addrtaken = true outer = Nod(OADDR, outer, nil) } @@ -259,7 +288,7 @@ func capturevars(xfunc *Node) { if v.Name.Byval { how = "value" } - Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Name.Param.Closure.Addrtaken, v.Name.Param.Closure.Assigned, int32(v.Type.Width)) + Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width)) } outer = typecheck(outer, Erv) diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 12a217753ac31b..9e7efdb3fc7a90 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -385,33 +385,36 @@ func oldname(s *Sym) *Node { } if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth { - // inner func is referring to var in outer func. + // Inner func is referring to var in outer func. // // TODO(rsc): If there is an outer variable x and we // are parsing x := 5 inside the closure, until we get to // the := it looks like a reference to the outer x so we'll // make x a closure variable unnecessarily. - if n.Name.Param.Closure == nil || n.Name.Param.Closure.Name.Funcdepth != Funcdepth { - // create new closure var. - c := Nod(ONAME, nil, nil) - + c := n.Name.Param.Innermost + if c == nil || c.Name.Funcdepth != Funcdepth { + // Do not have a closure var for the active closure yet; make one. + c = Nod(ONAME, nil, nil) c.Sym = s c.Class = PAUTOHEAP - c.setIsClosureParam(true) + c.setIsClosureVar(true) c.Isddd = n.Isddd c.Name.Defn = n c.Addable = false c.Ullman = 2 c.Name.Funcdepth = Funcdepth - c.Name.Param.Outer = n.Name.Param.Closure - n.Name.Param.Closure = c - c.Name.Param.Closure = n + + // Link into list of active closure variables. + // Popped from list in func closurebody. + c.Name.Param.Outer = n.Name.Param.Innermost + n.Name.Param.Innermost = c + c.Xoffset = 0 Curfn.Func.Cvars.Append(c) } // return ref to closure var, not original - return n.Name.Param.Closure + return c } return n diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 538c4842d90e81..d7365daaea3ab6 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -900,13 +900,13 @@ func esc(e *EscState, n *Node, up *Node) { escassignSinkNilWhy(e, n, n7.Right, "map literal value") } - // Link addresses of captured variables to closure. case OCLOSURE: + // Link addresses of captured variables to closure. for _, v := range n.Func.Cvars.Slice() { if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs continue } - a := v.Name.Param.Closure + a := v.Name.Defn if !v.Name.Byval { a = Nod(OADDR, a, nil) a.Lineno = v.Lineno @@ -1819,12 +1819,12 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep, // Treat a captured closure variable as equivalent to the // original variable. - if src.isClosureParam() { + if src.isClosureVar() { if leaks && Debug['m'] != 0 { Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort)) step.describe(src) } - escwalk(e, level, dst, src.Name.Param.Closure, e.stepWalk(dst, src.Name.Param.Closure, "closure-var", step)) + escwalk(e, level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step)) } case OPTRLIT, OADDR: diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index ee88eedcf3efa2..3d26a1d89b3029 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1193,7 +1193,7 @@ func exprfmt(n *Node, prec int) string { if n.Nbody.Len() != 0 { return fmt.Sprintf("%v { %v }", n.Type, n.Nbody) } - return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody) + return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody) case OCOMPLIT: ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr() diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index ec4a3c8142af72..3faf6d4a63cc9c 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -44,7 +44,7 @@ func addrescapes(n *Node) { } // If a closure reference escapes, mark the outer variable as escaping. - if n.isClosureParam() { + if n.isClosureVar() { addrescapes(n.Name.Defn) break } diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index cd4f2e6d62d8b4..d4bfc84d67a7a4 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -78,7 +78,7 @@ type Node struct { const ( hasBreak = 1 << iota notLiveAtEnd - isClosureParam + isClosureVar ) func (n *Node) HasBreak() bool { @@ -101,14 +101,14 @@ func (n *Node) SetNotLiveAtEnd(b bool) { n.flags &^= notLiveAtEnd } } -func (n *Node) isClosureParam() bool { - return n.flags&isClosureParam != 0 +func (n *Node) isClosureVar() bool { + return n.flags&isClosureVar != 0 } -func (n *Node) setIsClosureParam(b bool) { +func (n *Node) setIsClosureVar(b bool) { if b { - n.flags |= isClosureParam + n.flags |= isClosureVar } else { - n.flags &^= isClosureParam + n.flags &^= isClosureVar } } @@ -158,8 +158,8 @@ func (n *Node) SetOpt(x interface{}) { type Name struct { Pack *Node // real package for import . names Pkg *Pkg // pkg for OPACK nodes - Heapaddr *Node // temp holding heap address of param - Inlvar *Node // ONAME substitute while inlining + Heapaddr *Node // temp holding heap address of param (could move to Param?) + Inlvar *Node // ONAME substitute while inlining (could move to Param?) Defn *Node // initializing assignment Curfn *Node // function for local variables Param *Param // additional fields for ONAME, ODCLFIELD @@ -179,15 +179,82 @@ type Param struct { Ntype *Node // ONAME PAUTOHEAP - Outerexpr *Node // expression copied into closure for variable Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only) // ONAME PPARAM Field *Field // TFIELD in arg struct // ONAME closure linkage - Outer *Node - Closure *Node + // Consider: + // + // func f() { + // x := 1 // x1 + // func() { + // use(x) // x2 + // func() { + // use(x) // x3 + // --- parser is here --- + // }() + // }() + // } + // + // There is an original declaration of x and then a chain of mentions of x + // leading into the current function. Each time x is mentioned in a new closure, + // we create a variable representing x for use in that specific closure, + // since the way you get to x is different in each closure. + // + // Let's number the specific variables as shown in the code: + // x1 is the original x, x2 is when mentioned in the closure, + // and x3 is when mentioned in the closure in the closure. + // + // We keep these linked (assume N > 1): + // + // - x1.Defn = original declaration statement for x (like most variables) + // - x1.Innermost = current innermost closure x (in this case x3), or nil for none + // - x1.isClosureVar() = false + // + // - xN.Defn = x1, N > 1 + // - xN.isClosureVar() = true, N > 1 + // - x2.Outer = nil + // - xN.Outer = x(N-1), N > 2 + // + // + // When we look up x in the symbol table, we always get x1. + // Then we can use x1.Innermost (if not nil) to get the x + // for the innermost known closure function, + // but the first reference in a closure will find either no x1.Innermost + // or an x1.Innermost with .Funcdepth < Funcdepth. + // In that case, a new xN must be created, linked in with: + // + // xN.Defn = x1 + // xN.Outer = x1.Innermost + // x1.Innermost = xN + // + // When we finish the function, we'll process its closure variables + // and find xN and pop it off the list using: + // + // x1 := xN.Defn + // x1.Innermost = xN.Outer + // + // We leave xN.Innermost set so that we can still get to the original + // variable quickly. Not shown here, but once we're + // done parsing a function and no longer need xN.Outer for the + // lexical x reference links as described above, closurebody + // recomputes xN.Outer as the semantic x reference link tree, + // even filling in x in intermediate closures that might not + // have mentioned it along the way to inner closures that did. + // See closurebody for details. + // + // During the eventual compilation, then, for closure variables we have: + // + // xN.Defn = original variable + // xN.Outer = variable captured in next outward scope + // to make closure where xN appears + // + // Because of the sharding of pieces of the node, x.Defn means x.Name.Defn + // and x.Innermost/Outer means x.Name.Param.Innermost/Outer. + Innermost *Node + Outer *Node } // Func holds Node fields used only with function-like nodes. diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index bf4960a6daf088..c8ee9417e611f6 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -796,8 +796,8 @@ OpSwitch: var l *Node for l = n.Left; l != r; l = l.Left { l.Addrtaken = true - if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil { - l.Name.Param.Closure.Addrtaken = true + if l.isClosureVar() { + l.Name.Defn.Addrtaken = true } } @@ -805,8 +805,8 @@ OpSwitch: Fatalf("found non-orig name node %v", l) } l.Addrtaken = true - if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil { - l.Name.Param.Closure.Addrtaken = true + if l.isClosureVar() { + l.Name.Defn.Addrtaken = true } n.Left = defaultlit(n.Left, nil) l = n.Left @@ -3128,14 +3128,14 @@ func checkassign(stmt *Node, n *Node) { var l *Node for l = n; l != r; l = l.Left { l.Assigned = true - if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil { - l.Name.Param.Closure.Assigned = true + if l.isClosureVar() { + l.Name.Defn.Assigned = true } } l.Assigned = true - if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil { - l.Name.Param.Closure.Assigned = true + if l.isClosureVar() { + l.Name.Defn.Assigned = true } } From 605e751b53a8bec7d1f51b2ccc0093e063358dc6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 27 May 2016 11:05:14 -0400 Subject: [PATCH 258/267] net/http: change Transport.Dialer to Transport.DialContext New in Go 1.7 so still possible to change. This allows implementations not tied to *net.Dialer. Fixes #15748. Change-Id: I5fabbf13c7f1951c06587a4ccd120def488267ce Reviewed-on: https://go-review.googlesource.com/23489 Reviewed-by: Ian Lance Taylor --- src/net/http/transport.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 57ebbd57e12c44..43b20f2da2f86a 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -37,10 +37,10 @@ import ( // $no_proxy) environment variables. var DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, - Dialer: &net.Dialer{ + DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, - }, + }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, @@ -87,18 +87,18 @@ type Transport struct { // If Proxy is nil or returns a nil *URL, no proxy is used. Proxy func(*Request) (*url.URL, error) - // Dial specifies the dial function for creating unencrypted - // TCP connections. If Dial and Dialer are both nil, net.Dial - // is used. + // DialContext specifies the dial function for creating unencrypted TCP connections. + // If DialContext is nil (and the deprecated Dial below is also nil), + // then the transport dials using package net. + DialContext func(ctx context.Context, network, addr string) (net.Conn, error) + + // Dial specifies the dial function for creating unencrypted TCP connections. // - // Deprecated: Use Dialer instead. If both are specified, Dialer - // takes precedence. + // Deprecated: Use DialContext instead, which allows the transport + // to cancel dials as soon as they are no longer needed. + // If both are set, DialContext takes priority. Dial func(network, addr string) (net.Conn, error) - // Dialer optionally specifies a dialer configuration to use - // for new connections. - Dialer *net.Dialer - // DialTLS specifies an optional dial function for creating // TLS connections for non-proxied HTTPS requests. // @@ -777,8 +777,8 @@ func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool { var zeroDialer net.Dialer func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) { - if t.Dialer != nil { - return t.Dialer.DialContext(ctx, network, addr) + if t.DialContext != nil { + return t.DialContext(ctx, network, addr) } if t.Dial != nil { c, err := t.Dial(network, addr) From 52c2db7e6d68b68938d904864ee484e7b5dd5d52 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 27 May 2016 12:15:04 -0400 Subject: [PATCH 259/267] doc/go1.7.html: fix broken sentence Change-Id: Ia540c890767dcb001d3b3b55d98d9517b13b21da Reviewed-on: https://go-review.googlesource.com/23510 Reviewed-by: Ian Lance Taylor --- doc/go1.7.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/go1.7.html b/doc/go1.7.html index 7945622f6b8cad..46c575452f7765 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -532,8 +532,11 @@

Minor changes to the library

This heuristic reduces the amount of data that must be received before the first packet can be decrypted, improving communication latency over low-bandwidth networks. +Setting Config's -DynamicRecordSizingDisabled field to true. +DynamicRecordSizingDisabled field to true +forces the behavior of Go 1.6 and earlier, where packets are +as large as possible from the start of the connection.

From fa3543e33782fd90e0a8f36366d9889d39a7575e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 27 May 2016 09:50:06 -0400 Subject: [PATCH 260/267] crypto/tls: adjust dynamic record sizes to grow arithmetically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code, introduced after Go 1.6 to improve latency on low-bandwidth connections, sends 1 kB packets until 1 MB has been sent, and then sends 16 kB packets (the maximum record size). Unfortunately this decreases throughput for 1-16 MB responses by 20% or so. Following discussion on #15713, change cutoff to 128 kB sent and also grow the size allowed for successive packets: 1 kB, 2 kB, 3 kB, ..., 15 kB, 16 kB. This fixes the throughput problems: the overhead is now closer to 2%. I hope this still helps with latency but I don't have a great way to test it. At the least, it's not worse than Go 1.6. Comparing MaxPacket vs DynamicPacket benchmarks: name maxpkt time/op dyn. time/op delta Throughput/1MB-8 5.07ms ± 7% 5.21ms ± 7% +2.73% (p=0.023 n=16+16) Throughput/2MB-8 15.7ms ±201% 8.4ms ± 5% ~ (p=0.604 n=20+16) Throughput/4MB-8 14.3ms ± 1% 14.5ms ± 1% +1.53% (p=0.000 n=16+16) Throughput/8MB-8 26.6ms ± 1% 26.8ms ± 1% +0.47% (p=0.003 n=19+18) Throughput/16MB-8 51.0ms ± 1% 51.3ms ± 1% +0.47% (p=0.000 n=20+20) Throughput/32MB-8 100ms ± 1% 100ms ± 1% +0.24% (p=0.033 n=20+20) Throughput/64MB-8 197ms ± 0% 198ms ± 0% +0.56% (p=0.000 n=18+7) The small MB runs are bimodal in both cases, probably GC pauses. But there's clearly no general slowdown anymore. Fixes #15713. Change-Id: I5fc44680ba71812d24baac142bceee0e23f2e382 Reviewed-on: https://go-review.googlesource.com/23487 Reviewed-by: Ian Lance Taylor --- src/crypto/tls/conn.go | 24 ++++-- src/crypto/tls/conn_test.go | 11 +-- src/crypto/tls/tls_test.go | 153 +++++++++++++++++++++++++++++++++++- 3 files changed, 174 insertions(+), 14 deletions(-) diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index c4f8b0816b0b00..f93a5f28ae66ca 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -76,10 +76,11 @@ type Conn struct { input *block // application data waiting to be read hand bytes.Buffer // handshake data waiting to be read - // bytesSent counts the number of bytes of application data that have - // been sent. + // bytesSent counts the bytes of application data sent. + // packetsSent counts packets. bytesSent int64 - + packetsSent int64 + // activeCall is an atomic int32; the low bit is whether Close has // been called. the rest of the bits are the number of goroutines // in Conn.Write. @@ -732,7 +733,7 @@ const ( // recordSizeBoostThreshold is the number of bytes of application data // sent after which the TLS record size will be increased to the // maximum. - recordSizeBoostThreshold = 1 * 1024 * 1024 + recordSizeBoostThreshold = 128 * 1024 ) // maxPayloadSizeForWrite returns the maximum TLS payload size to use for the @@ -787,8 +788,19 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int { panic("unknown cipher type") } } - - return payloadBytes + + // Allow packet growth in arithmetic progression up to max. + pkt := c.packetsSent + c.packetsSent++ + if pkt > 1000 { + return maxPlaintext // avoid overflow in multiply below + } + + n := payloadBytes * int(pkt + 1) + if n > maxPlaintext { + n = maxPlaintext + } + return n } // writeRecordLocked writes a TLS record with the given type and payload to the diff --git a/src/crypto/tls/conn_test.go b/src/crypto/tls/conn_test.go index 8334d90839cded..4e4bbc95e86d24 100644 --- a/src/crypto/tls/conn_test.go +++ b/src/crypto/tls/conn_test.go @@ -208,13 +208,10 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) { seenLargeRecord := false for i, size := range recordSizes { if !seenLargeRecord { - if size > tcpMSSEstimate { - if i < 100 { - t.Fatalf("Record #%d has size %d, which is too large too soon", i, size) - } - if size <= maxPlaintext { - t.Fatalf("Record #%d has odd size %d", i, size) - } + if size > (i+1)*tcpMSSEstimate { + t.Fatalf("Record #%d has size %d, which is too large too soon", i, size) + } + if size >= maxPlaintext { seenLargeRecord = true } } else if size <= maxPlaintext { diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index 1a33658a1e365b..4fbe4b26b60271 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -10,6 +10,7 @@ import ( "fmt" "internal/testenv" "io" + "math" "net" "strings" "testing" @@ -146,7 +147,7 @@ func TestX509MixedKeyPair(t *testing.T) { } } -func newLocalListener(t *testing.T) net.Listener { +func newLocalListener(t testing.TB) net.Listener { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { ln, err = net.Listen("tcp6", "[::1]:0") @@ -473,3 +474,153 @@ func (w *changeImplConn) Close() error { } return w.Conn.Close() } + +func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool) { + ln := newLocalListener(b) + defer ln.Close() + + var serr error + go func() { + for i := 0; i < b.N; i++ { + sconn, err := ln.Accept() + if err != nil { + serr = err + return + } + serverConfig := *testConfig + serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled + srv := Server(sconn, &serverConfig) + if err := srv.Handshake(); err != nil { + serr = fmt.Errorf("handshake: %v", err) + return + } + io.Copy(srv, srv) + } + }() + + b.SetBytes(totalBytes) + clientConfig := *testConfig + clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled + + buf := make([]byte, 1<<16) + chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf)))) + for i := 0; i < b.N; i++ { + conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) + if err != nil { + b.Fatal(err) + } + for j := 0; j < chunks; j++ { + _, err := conn.Write(buf) + if err != nil { + b.Fatal(err) + } + _, err = io.ReadFull(conn, buf) + if err != nil { + b.Fatal(err) + } + } + conn.Close() + } +} + +func BenchmarkThroughput(b *testing.B) { + for _, mode := range []string{"Max", "Dynamic"} { + for size := 1; size <= 64; size<<=1{ + name := fmt.Sprintf("%sPacket/%dMB", mode, size) + b.Run(name, func(b *testing.B) { + throughput(b, int64(size<<20), mode == "Max") + }) + } + } +} + +type slowConn struct { + net.Conn + bps int +} + +func (c *slowConn) Write(p []byte) (int, error) { + if c.bps == 0 { + panic("too slow") + } + t0 := time.Now() + wrote := 0 + for wrote < len(p) { + time.Sleep(100*time.Microsecond) + allowed := int(time.Since(t0).Seconds() * float64(c.bps)) / 8 + if allowed > len(p) { + allowed = len(p) + } + if wrote < allowed { + n, err := c.Conn.Write(p[wrote:allowed]) + wrote += n + if err != nil { + return wrote, err + } + } + } + return len(p), nil +} + +func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) { + ln := newLocalListener(b) + defer ln.Close() + + var serr error + go func() { + for i := 0; i < b.N; i++ { + sconn, err := ln.Accept() + if err != nil { + serr = err + return + } + serverConfig := *testConfig + serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled + srv := Server(&slowConn{sconn, bps}, &serverConfig) + if err := srv.Handshake(); err != nil { + serr = fmt.Errorf("handshake: %v", err) + return + } + io.Copy(srv, srv) + } + }() + + clientConfig := *testConfig + clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled + + buf := make([]byte, 16384) + peek := make([]byte, 1) + + for i := 0; i < b.N; i++ { + conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) + if err != nil { + b.Fatal(err) + } + // make sure we're connected and previous connection has stopped + if _, err := conn.Write(buf[:1]); err != nil { + b.Fatal(err) + } + if _, err := io.ReadFull(conn, peek); err != nil { + b.Fatal(err) + } + if _, err := conn.Write(buf); err != nil { + b.Fatal(err) + } + if _, err = io.ReadFull(conn, peek); err != nil { + b.Fatal(err) + } + conn.Close() + } +} + + +func BenchmarkLatency(b *testing.B) { + for _, mode := range []string{"Max", "Dynamic"} { + for _, kbps := range []int{200, 500, 1000, 2000, 5000} { + name := fmt.Sprintf("%sPacket/%dkbps", mode, kbps) + b.Run(name, func(b *testing.B) { + latency(b, kbps*1000, mode == "Max") + }) + } + } +} From 966baedfea6b09fa203b0cf0e6388830cc9f9fa7 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 26 May 2016 11:05:01 -0400 Subject: [PATCH 261/267] runtime: record Python stack on TestGdbPython failure For #15599. Change-Id: Icc2e58a3f314b7a098d78fe164ba36f5b2897de6 Reviewed-on: https://go-review.googlesource.com/23481 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/runtime-gdb_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 0ad88565148d2e..e109fa45288a97 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -100,6 +100,7 @@ func TestGdbPython(t *testing.T) { fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()), "-ex", "set startup-with-shell off", "-ex", "info auto-load python-scripts", + "-ex", "set python print-stack full", "-ex", "br main.go:10", "-ex", "run", "-ex", "echo BEGIN info goroutines\n", From 6a86dbe75f6d5a135eefbae807d98e856136514f Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 27 May 2016 12:21:14 -0400 Subject: [PATCH 262/267] runtime: always call stackfree on the system stack Currently when the garbage collector frees stacks of dead goroutines in markrootFreeGStacks, it calls stackfree on a regular user stack. This is a problem, since stackfree manipulates the stack cache in the per-P mcache, so if it grows the stack or gets preempted in the middle of manipulating the stack cache (which are both possible since it's on a user stack), it can easily corrupt the stack cache. Fix this by calling markrootFreeGStacks on the system stack, so that all calls to stackfree happen on the system stack. To prevent this bug in the future, mark stack functions that manipulate the mcache as go:systemstack. Fixes #15853. Change-Id: Ic0d1c181efb342f134285a152560c3a074f14a3d Reviewed-on: https://go-review.googlesource.com/23511 Run-TryBot: Austin Clements Reviewed-by: Keith Randall Reviewed-by: Rick Hudson TryBot-Result: Gobot Gobot --- src/runtime/mgcmark.go | 4 +++- src/runtime/stack.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 2d0cbd203c219f..00b96fd00beed2 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -174,7 +174,9 @@ func markroot(gcw *gcWork, i uint32) { // Only do this once per GC cycle; preferably // concurrently. if !work.markrootDone { - markrootFreeGStacks() + // Switch to the system stack so we can call + // stackfree. + systemstack(markrootFreeGStacks) } case baseSpans <= i && i < baseStacks: diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 8e344cdf03585c..ee2797e1443300 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -251,6 +251,8 @@ func stackpoolfree(x gclinkptr, order uint8) { // stackcacherefill/stackcacherelease implement a global pool of stack segments. // The pool is required to prevent unlimited growth of per-thread caches. +// +//go:systemstack func stackcacherefill(c *mcache, order uint8) { if stackDebug >= 1 { print("stackcacherefill order=", order, "\n") @@ -272,6 +274,7 @@ func stackcacherefill(c *mcache, order uint8) { c.stackcache[order].size = size } +//go:systemstack func stackcacherelease(c *mcache, order uint8) { if stackDebug >= 1 { print("stackcacherelease order=", order, "\n") @@ -290,6 +293,7 @@ func stackcacherelease(c *mcache, order uint8) { c.stackcache[order].size = size } +//go:systemstack func stackcache_clear(c *mcache) { if stackDebug >= 1 { print("stackcache clear\n") @@ -308,6 +312,12 @@ func stackcache_clear(c *mcache) { unlock(&stackpoolmu) } +// stackalloc allocates an n byte stack. +// +// stackalloc must run on the system stack because it uses per-P +// resources and must not split the stack. +// +//go:systemstack func stackalloc(n uint32) (stack, []stkbar) { // Stackalloc must be called on scheduler stack, so that we // never try to grow the stack during the code that stackalloc runs. @@ -405,6 +415,12 @@ func stackalloc(n uint32) (stack, []stkbar) { return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice)) } +// stackfree frees an n byte stack allocation at stk. +// +// stackfree must run on the system stack because it uses per-P +// resources and must not split the stack. +// +//go:systemstack func stackfree(stk stack, n uintptr) { gp := getg() v := unsafe.Pointer(stk.lo) From c340f4867b61d0c9dab167df88f56efc4ed7f17b Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 27 May 2016 17:34:22 +0900 Subject: [PATCH 263/267] runtime: skip TestGdbBacktrace on netbsd Also adds missing copyright notice. Updates #15603. Change-Id: Icf4bb45ba5edec891491fe5f0039a8a25125d168 Reviewed-on: https://go-review.googlesource.com/23501 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/runtime-gdb_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index e109fa45288a97..aabe52da3c4231 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -1,3 +1,7 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package runtime_test import ( @@ -207,6 +211,10 @@ func TestGdbBacktrace(t *testing.T) { checkGdbEnvironment(t) checkGdbVersion(t) + if runtime.GOOS == "netbsd" { + testenv.SkipFlaky(t, 15603) + } + dir, err := ioutil.TempDir("", "go-build") if err != nil { t.Fatalf("failed to create temp directory: %v", err) From b0b2f7d6dda2b01a06a1dd99b87c97c81934c184 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 27 May 2016 17:35:45 +0900 Subject: [PATCH 264/267] net/http/httptrace: fix nit in test Change-Id: I6dc3666398b4cd7a7195bb9c0e321fa8b733fa15 Reviewed-on: https://go-review.googlesource.com/23502 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/net/http/httptrace/trace_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/httptrace/trace_test.go b/src/net/http/httptrace/trace_test.go index ed6ddbb40dbd17..c7eaed83d47851 100644 --- a/src/net/http/httptrace/trace_test.go +++ b/src/net/http/httptrace/trace_test.go @@ -16,7 +16,7 @@ func TestCompose(t *testing.T) { connectStart := func(b byte) func(network, addr string) { return func(network, addr string) { if addr != "addr" { - t.Errorf(`%d. args for %Q case = %q, %q; want addr of "addr"`, testNum, b, network, addr) + t.Errorf(`%d. args for %q case = %q, %q; want addr of "addr"`, testNum, b, network, addr) } buf.WriteByte(b) } From 53af0d3476e3c5f5b71f0c5fcf2141c24cc102b2 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 28 May 2016 03:20:11 +0900 Subject: [PATCH 265/267] crypto/tls: fix race in Benchmark{Throughput,Latency} Fixes #15864. Change-Id: Ic12aa3654bf0b7e4a26df20ea92d07d7efe7339c Reviewed-on: https://go-review.googlesource.com/23504 Reviewed-by: David Chase --- src/crypto/tls/tls_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index 4fbe4b26b60271..8dc4533a52da4b 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -479,9 +479,11 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool ln := newLocalListener(b) defer ln.Close() + N := b.N + var serr error go func() { - for i := 0; i < b.N; i++ { + for i := 0; i < N; i++ { sconn, err := ln.Accept() if err != nil { serr = err @@ -504,7 +506,7 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool buf := make([]byte, 1<<16) chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf)))) - for i := 0; i < b.N; i++ { + for i := 0; i < N; i++ { conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) if err != nil { b.Fatal(err) @@ -566,9 +568,11 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) { ln := newLocalListener(b) defer ln.Close() + N := b.N + var serr error go func() { - for i := 0; i < b.N; i++ { + for i := 0; i < N; i++ { sconn, err := ln.Accept() if err != nil { serr = err @@ -591,7 +595,7 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) { buf := make([]byte, 16384) peek := make([]byte, 1) - for i := 0; i < b.N; i++ { + for i := 0; i < N; i++ { conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) if err != nil { b.Fatal(err) From e149624ebb00a2fcc59bc02b9f122e3c4bae6e9c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 27 May 2016 14:24:26 -0400 Subject: [PATCH 266/267] cmd/compile/internal/gc: gofmt Commit 36a80c5 introduced formatting errors. Change-Id: I6d5b231200cd7abcd5b94c1a3f4e99f10ee11c4f Reviewed-on: https://go-review.googlesource.com/23513 Reviewed-by: David Chase Run-TryBot: David Chase --- src/cmd/compile/internal/gc/closure.go | 2 +- src/cmd/compile/internal/gc/dcl.go | 7 +++---- src/cmd/compile/internal/gc/syntax.go | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 6d84aed7b108f0..ecdf19a2c4293a 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -69,7 +69,7 @@ func closurebody(body []*Node) *Node { // Unlink from v1; see comment in syntax.go type Param for these fields. v1 := v.Name.Defn v1.Name.Param.Innermost = v.Name.Param.Outer - + // If the closure usage of v is not dense, // we need to make it dense; now that we're out // of the function in which v appeared, diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 9e7efdb3fc7a90..a4b98ec7c5219a 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -403,7 +403,7 @@ func oldname(s *Sym) *Node { c.Addable = false c.Ullman = 2 c.Name.Funcdepth = Funcdepth - + // Link into list of active closure variables. // Popped from list in func closurebody. c.Name.Param.Outer = n.Name.Param.Innermost @@ -508,7 +508,7 @@ func ifacedcl(n *Node) { n.Func = new(Func) n.Func.FCurfn = Curfn dclcontext = PPARAM - + funcstart(n) funcargs(n.Right) @@ -670,8 +670,7 @@ func funcargs2(t *Type) { } var funcstack []*Node // stack of previous values of Curfn -var Funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation - +var Funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation // start the function. // called before funcargs; undone at end of funcbody. diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index d4bfc84d67a7a4..e673db9004804c 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -156,16 +156,16 @@ func (n *Node) SetOpt(x interface{}) { // Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, ODCLFIELD, some OLITERAL). type Name struct { - Pack *Node // real package for import . names - Pkg *Pkg // pkg for OPACK nodes - Heapaddr *Node // temp holding heap address of param (could move to Param?) - Inlvar *Node // ONAME substitute while inlining (could move to Param?) - Defn *Node // initializing assignment - Curfn *Node // function for local variables + Pack *Node // real package for import . names + Pkg *Pkg // pkg for OPACK nodes + Heapaddr *Node // temp holding heap address of param (could move to Param?) + Inlvar *Node // ONAME substitute while inlining (could move to Param?) + Defn *Node // initializing assignment + Curfn *Node // function for local variables Param *Param // additional fields for ONAME, ODCLFIELD - Decldepth int32 // declaration loop depth, increased for every loop or label - Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one. - Iota int32 // value if this name is iota + Decldepth int32 // declaration loop depth, increased for every loop or label + Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one. + Iota int32 // value if this name is iota Funcdepth int32 Method bool // OCALLMETH name Readonly bool @@ -254,7 +254,7 @@ type Param struct { // Because of the sharding of pieces of the node, x.Defn means x.Name.Defn // and x.Innermost/Outer means x.Name.Param.Innermost/Outer. Innermost *Node - Outer *Node + Outer *Node } // Func holds Node fields used only with function-like nodes. From 496cf215cf7f36c2b1b14c00aadccf3e16f67eae Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 27 May 2016 14:25:16 -0400 Subject: [PATCH 267/267] crypto/tls: gofmt Commit fa3543e introduced formatting errors. Change-Id: I4b921f391a9b463cefca4318ad63b70ae6ce6865 Reviewed-on: https://go-review.googlesource.com/23514 Reviewed-by: David Chase Run-TryBot: David Chase --- src/crypto/tls/conn.go | 10 +++++----- src/crypto/tls/tls_test.go | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index f93a5f28ae66ca..40c17440d652dc 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -78,9 +78,9 @@ type Conn struct { // bytesSent counts the bytes of application data sent. // packetsSent counts packets. - bytesSent int64 + bytesSent int64 packetsSent int64 - + // activeCall is an atomic int32; the low bit is whether Close has // been called. the rest of the bits are the number of goroutines // in Conn.Write. @@ -788,15 +788,15 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int { panic("unknown cipher type") } } - + // Allow packet growth in arithmetic progression up to max. pkt := c.packetsSent c.packetsSent++ if pkt > 1000 { return maxPlaintext // avoid overflow in multiply below } - - n := payloadBytes * int(pkt + 1) + + n := payloadBytes * int(pkt+1) if n > maxPlaintext { n = maxPlaintext } diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index 8dc4533a52da4b..894d7e82ab75c4 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -527,7 +527,7 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool func BenchmarkThroughput(b *testing.B) { for _, mode := range []string{"Max", "Dynamic"} { - for size := 1; size <= 64; size<<=1{ + for size := 1; size <= 64; size <<= 1 { name := fmt.Sprintf("%sPacket/%dMB", mode, size) b.Run(name, func(b *testing.B) { throughput(b, int64(size<<20), mode == "Max") @@ -548,8 +548,8 @@ func (c *slowConn) Write(p []byte) (int, error) { t0 := time.Now() wrote := 0 for wrote < len(p) { - time.Sleep(100*time.Microsecond) - allowed := int(time.Since(t0).Seconds() * float64(c.bps)) / 8 + time.Sleep(100 * time.Microsecond) + allowed := int(time.Since(t0).Seconds()*float64(c.bps)) / 8 if allowed > len(p) { allowed = len(p) } @@ -617,7 +617,6 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) { } } - func BenchmarkLatency(b *testing.B) { for _, mode := range []string{"Max", "Dynamic"} { for _, kbps := range []int{200, 500, 1000, 2000, 5000} {