]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.ssa] Merge branch 'master' into dev.ssa
authorDavid Chase <drchase@google.com>
Fri, 27 May 2016 19:18:49 +0000 (15:18 -0400)
committerDavid Chase <drchase@google.com>
Fri, 27 May 2016 19:19:33 +0000 (15:19 -0400)
Change-Id: Iabc80b6e0734efbd234d998271e110d2eaad41dd

507 files changed:
.gitignore
AUTHORS
CONTRIBUTORS
api/next.txt
doc/cmd.html
doc/contribute.html
doc/effective_go.html
doc/go1.7.html [new file with mode: 0644]
doc/go1.7.txt [deleted file]
doc/install-source.html
doc/install.html
misc/cgo/errors/issue14669.go [new file with mode: 0644]
misc/cgo/errors/ptr.go
misc/cgo/errors/test.bash
misc/cgo/testcarchive/carchive_test.go
misc/cgo/testcarchive/main4.c
misc/cgo/testsanitizers/test.bash
misc/cgo/testsanitizers/tsan3.go [new file with mode: 0644]
misc/cgo/testsanitizers/tsan4.go [new file with mode: 0644]
misc/nacl/testzip.proto
src/archive/tar/common.go
src/archive/tar/format.go [new file with mode: 0644]
src/archive/tar/reader.go
src/archive/tar/writer.go
src/archive/tar/writer_test.go
src/archive/zip/struct.go
src/bufio/bufio_test.go
src/bytes/reader.go
src/bytes/reader_test.go
src/cmd/asm/internal/arch/amd64.go [new file with mode: 0644]
src/cmd/asm/internal/asm/asm.go
src/cmd/asm/internal/asm/testdata/amd64enc.s
src/cmd/cgo/gcc.go
src/cmd/cgo/out.go
src/cmd/compile/doc.go
src/cmd/compile/internal/amd64/galign.go
src/cmd/compile/internal/amd64/gsubr.go
src/cmd/compile/internal/amd64/reg.go
src/cmd/compile/internal/amd64/ssa.go
src/cmd/compile/internal/arm/gsubr.go
src/cmd/compile/internal/gc/align.go
src/cmd/compile/internal/gc/asm_test.go [new file with mode: 0644]
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/cgen.go
src/cmd/compile/internal/gc/closure.go
src/cmd/compile/internal/gc/constFold_test.go [new file with mode: 0644]
src/cmd/compile/internal/gc/cplx.go
src/cmd/compile/internal/gc/dcl.go
src/cmd/compile/internal/gc/esc.go
src/cmd/compile/internal/gc/export.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/gen.go
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/gsubr.go
src/cmd/compile/internal/gc/init.go
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/logic_test.go [new file with mode: 0644]
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/mkbuiltin.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/gc/opnames.go
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/gc/parser.go
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/racewalk.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/sizeof_test.go
src/cmd/compile/internal/gc/sparselocatephifunctions.go [new file with mode: 0644]
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/ssa_test.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go [new file with mode: 0644]
src/cmd/compile/internal/gc/type.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/universe.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/mips64/gsubr.go
src/cmd/compile/internal/ssa/check.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/config.go
src/cmd/compile/internal/ssa/cse.go
src/cmd/compile/internal/ssa/dom.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/gen/rulegen.go
src/cmd/compile/internal/ssa/likelyadjust.go
src/cmd/compile/internal/ssa/lower.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/passbm_test.go
src/cmd/compile/internal/ssa/prove.go
src/cmd/compile/internal/ssa/redblack32.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/redblack32_test.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/regalloc.go
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/sparsemap.go
src/cmd/compile/internal/ssa/sparseset.go
src/cmd/compile/internal/ssa/sparsetree.go
src/cmd/compile/internal/ssa/sparsetreemap.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/stackalloc.go
src/cmd/compile/internal/x86/gsubr.go
src/cmd/cover/cover.go
src/cmd/dist/build.go
src/cmd/dist/buildgo.go
src/cmd/dist/test.go
src/cmd/go/alldocs.go
src/cmd/go/build.go
src/cmd/go/go_test.go
src/cmd/go/note.go
src/cmd/go/test.go
src/cmd/go/vcs.go
src/cmd/go/vcs_test.go
src/cmd/internal/goobj/read.go
src/cmd/internal/obj/go.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/sym.go
src/cmd/internal/obj/util.go
src/cmd/internal/obj/x86/a.out.go
src/cmd/internal/obj/x86/anames.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/internal/objfile/disasm.go
src/cmd/internal/pprof/commands/commands.go
src/cmd/internal/pprof/report/report.go
src/cmd/internal/pprof/tempfile/tempfile.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/go.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/objfile.go
src/cmd/pack/pack.go
src/cmd/trace/main.go
src/cmd/trace/trace.go
src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile with 100% similarity]
src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt [moved from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go with 100% similarity]
src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go [moved from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go with 100% similarity]
src/cmd/vendor/vendor.json [moved from src/cmd/internal/unvendor/vendor.json with 100% similarity]
src/cmd/vet/print.go
src/cmd/vet/testdata/copylock.go
src/cmd/vet/testdata/print.go
src/compress/flate/reader_test.go
src/compress/flate/writer_test.go
src/compress/gzip/gunzip.go
src/compress/lzw/reader_test.go
src/compress/lzw/writer_test.go
src/compress/zlib/reader.go
src/container/list/list_test.go
src/context/context.go
src/context/context_test.go
src/crypto/cipher/example_test.go
src/crypto/ecdsa/ecdsa.go
src/crypto/ecdsa/ecdsa_test.go
src/crypto/elliptic/p256_amd64.go
src/crypto/sha1/issue15617_test.go [new file with mode: 0644]
src/crypto/sha1/sha1_test.go
src/crypto/sha1/sha1block_amd64.go [new file with mode: 0644]
src/crypto/sha1/sha1block_amd64.s
src/crypto/sha1/sha1block_decl.go
src/crypto/sha256/sha256block_amd64.s
src/crypto/tls/conn.go
src/crypto/tls/conn_test.go
src/crypto/tls/handshake_server.go
src/crypto/tls/handshake_server_test.go
src/crypto/tls/tls.go
src/crypto/tls/tls_test.go
src/crypto/x509/root_cgo_darwin.go
src/crypto/x509/x509.go
src/debug/elf/file_test.go
src/debug/elf/reader.go
src/debug/gosym/pclntab_test.go
src/debug/gosym/symtab.go
src/debug/gosym/symtab_test.go [new file with mode: 0644]
src/encoding/csv/reader.go
src/encoding/gob/codec_test.go
src/encoding/json/decode.go
src/encoding/json/decode_test.go
src/encoding/json/encode.go
src/encoding/json/example_test.go
src/encoding/json/stream.go
src/encoding/json/stream_test.go
src/expvar/expvar.go
src/fmt/doc.go
src/go/build/build.go
src/go/build/deps_test.go
src/go/internal/gccgoimporter/importer.go
src/go/internal/gcimporter/bimport.go
src/go/internal/gcimporter/gcimporter.go
src/go/internal/gcimporter/gcimporter_test.go
src/go/internal/gcimporter/testdata/p.go [new file with mode: 0644]
src/go/token/position.go
src/go/types/assignments.go
src/go/types/decl.go
src/go/types/resolver.go
src/go/types/stmt.go
src/go/types/testdata/issues.src
src/go/types/testdata/stmt0.src
src/hash/crc64/crc64.go
src/hash/crc64/crc64_test.go
src/html/template/content.go
src/internal/nettrace/nettrace.go
src/internal/syscall/windows/registry/syscall.go
src/internal/syscall/windows/registry/zsyscall_windows.go
src/internal/syscall/windows/syscall_windows.go
src/internal/syscall/windows/zsyscall_windows.go
src/internal/testenv/testenv.go
src/io/example_test.go
src/io/io.go
src/io/io_test.go
src/io/multi.go
src/io/multi_test.go
src/make.bash
src/make.bat
src/make.rc
src/math/big/arith_test.go
src/math/big/nat_test.go
src/math/big/natconv.go
src/math/big/natconv_test.go
src/math/rand/rand.go
src/mime/multipart/writer.go
src/mime/multipart/writer_test.go
src/mime/type_plan9.go
src/net/cgo_stub.go
src/net/cgo_unix.go
src/net/cgo_unix_test.go
src/net/conn_test.go
src/net/dial.go
src/net/dial_test.go
src/net/dnsclient_unix_test.go
src/net/error_test.go
src/net/fd_plan9.go
src/net/fd_unix.go
src/net/fd_windows.go
src/net/file_plan9.go
src/net/http/client.go
src/net/http/client_test.go
src/net/http/clientserver_test.go
src/net/http/export_test.go
src/net/http/h2_bundle.go
src/net/http/http.go
src/net/http/httptest/recorder.go
src/net/http/httptest/recorder_test.go
src/net/http/httptrace/trace.go
src/net/http/httptrace/trace_test.go
src/net/http/httputil/reverseproxy.go
src/net/http/httputil/reverseproxy_test.go
src/net/http/internal/chunked_test.go
src/net/http/request.go
src/net/http/request_test.go
src/net/http/response.go
src/net/http/serve_test.go
src/net/http/server.go
src/net/http/status.go
src/net/http/transfer.go
src/net/http/transport.go
src/net/http/transport_internal_test.go [new file with mode: 0644]
src/net/http/transport_test.go
src/net/interface_bsd.go
src/net/interface_bsd_test.go
src/net/interface_bsdvar.go [moved from src/net/interface_netbsd.go with 54% similarity]
src/net/interface_darwin.go
src/net/interface_dragonfly.go [deleted file]
src/net/interface_freebsd.go
src/net/interface_linux.go
src/net/interface_openbsd.go [deleted file]
src/net/interface_test.go
src/net/interface_unix_test.go
src/net/interface_windows.go
src/net/ip.go
src/net/ip_test.go
src/net/lookup_plan9.go
src/net/lookup_test.go
src/net/lookup_unix.go
src/net/mockserver_test.go
src/net/net.go
src/net/net_test.go
src/net/netgo_unix_test.go
src/net/timeout_test.go
src/net/url/url.go
src/net/url/url_test.go
src/os/exec/exec.go
src/os/exec/exec_test.go
src/os/exec/lp_plan9.go
src/os/exec/lp_unix.go
src/os/exec/lp_windows.go
src/os/exec/lp_windows_test.go
src/os/file_plan9.go
src/os/file_windows.go
src/os/os_test.go
src/os/os_unix_test.go
src/os/os_windows_test.go
src/os/signal/doc.go
src/os/user/getgrouplist_darwin.go [moved from src/os/user/getgrouplist_darwin.c with 64% similarity]
src/os/user/getgrouplist_unix.go [moved from src/os/user/getgrouplist_unix.c with 56% similarity]
src/os/user/listgroups_unix.go
src/path/filepath/match.go
src/path/filepath/match_test.go
src/reflect/all_test.go
src/reflect/export_test.go
src/reflect/type.go
src/regexp/syntax/doc.go
src/run.bash
src/run.bat
src/run.rc
src/runtime/append_test.go
src/runtime/asm_amd64.s
src/runtime/cgo.go
src/runtime/cgo/asm_arm.s
src/runtime/cgo/callbacks.go
src/runtime/cgo/gcc_openbsd_386.c
src/runtime/cgo/gcc_openbsd_amd64.c
src/runtime/cgo/gcc_util.c
src/runtime/cgocall.go
src/runtime/cgocheck.go
src/runtime/crash_unix_test.go
src/runtime/malloc.go
src/runtime/mbitmap.go
src/runtime/memmove_test.go
src/runtime/mfinal.go
src/runtime/mgc.go
src/runtime/mgcmark.go
src/runtime/mheap.go
src/runtime/os1_freebsd.go [deleted file]
src/runtime/os1_nacl.go [deleted file]
src/runtime/os1_openbsd.go [deleted file]
src/runtime/os1_plan9.go [deleted file]
src/runtime/os_freebsd.go
src/runtime/os_linux_mips64x.go
src/runtime/os_linux_noauxv.go
src/runtime/os_nacl.go
src/runtime/os_openbsd.go
src/runtime/os_plan9.go
src/runtime/pprof/pprof_test.go
src/runtime/proc.go
src/runtime/proc_test.go
src/runtime/race.go
src/runtime/race/testdata/chan_test.go
src/runtime/rt0_darwin_amd64.s
src/runtime/rt0_darwin_arm.s
src/runtime/rt0_linux_arm.s
src/runtime/rt0_linux_ppc64le.s
src/runtime/runtime-gdb_test.go
src/runtime/runtime-lldb_test.go
src/runtime/runtime1.go
src/runtime/runtime2.go
src/runtime/signal1_unix.go
src/runtime/softfloat_arm.go
src/runtime/stack.go
src/runtime/sys_openbsd_386.s
src/runtime/sys_windows_amd64.s
src/runtime/testdata/testprog/gc.go
src/runtime/testdata/testprog/signal.go
src/runtime/testdata/testprogcgo/threadpanic_windows.c
src/runtime/traceback.go
src/runtime/type.go
src/strings/reader.go
src/strings/strings_amd64.go
src/strings/strings_test.go
src/sync/atomic/value.go
src/sync/cond.go
src/sync/mutex.go
src/sync/pool.go
src/sync/rwmutex.go
src/sync/waitgroup.go
src/syscall/bpf_bsd.go
src/syscall/exec_linux.go
src/syscall/exec_linux_test.go
src/syscall/exec_plan9.go
src/syscall/fd_nacl.go
src/syscall/fs_nacl.go
src/syscall/lsf_linux.go
src/syscall/mksyscall_windows.go
src/syscall/route_bsd.go
src/syscall/route_bsd_test.go [deleted file]
src/syscall/route_darwin.go
src/syscall/route_dragonfly.go
src/syscall/route_freebsd.go
src/syscall/route_ifma_test.go [deleted file]
src/syscall/route_netbsd.go
src/syscall/route_noifma_test.go [deleted file]
src/syscall/route_openbsd.go
src/syscall/syscall_plan9.go
src/syscall/syscall_unix_test.go
src/syscall/zsyscall_darwin_386.go
src/syscall/zsyscall_darwin_amd64.go
src/syscall/zsyscall_darwin_arm.go
src/syscall/zsyscall_dragonfly_amd64.go
src/syscall/zsyscall_freebsd_386.go
src/syscall/zsyscall_freebsd_amd64.go
src/syscall/zsyscall_freebsd_arm.go
src/syscall/zsyscall_netbsd_386.go
src/syscall/zsyscall_netbsd_amd64.go
src/syscall/zsyscall_netbsd_arm.go
src/syscall/zsyscall_openbsd_386.go
src/syscall/zsyscall_openbsd_amd64.go
src/testing/match_test.go
src/testing/quick/quick.go
src/testing/quick/quick_test.go
src/testing/sub_test.go
src/testing/testing.go
src/text/scanner/example_test.go
src/text/scanner/scanner.go
src/text/scanner/scanner_test.go
src/text/template/doc.go
src/text/template/exec.go
src/text/template/exec_test.go
src/time/sleep.go
src/time/sys_plan9.go
src/time/sys_unix.go
src/time/sys_windows.go
src/time/zoneinfo_abbrs_windows.go
src/time/zoneinfo_read.go
src/time/zoneinfo_test.go
src/time/zoneinfo_windows.go
src/vendor/golang.org/x/net/http2/hpack/hpack_test.go
src/vendor/golang.org/x/net/http2/hpack/huffman.go
src/vendor/golang.org/x/net/lex/httplex/httplex.go [moved from src/net/http/lex.go with 73% similarity]
src/vendor/golang.org/x/net/lex/httplex/httplex_test.go [moved from src/net/http/lex_test.go with 94% similarity]
src/vendor/golang.org/x/net/route/address.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/address_darwin_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/address_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/binary.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/defs_darwin.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/defs_dragonfly.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/defs_freebsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/defs_netbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/defs_openbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface_announce.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface_classic.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface_freebsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface_multicast.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/interface_openbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/message.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/message_darwin_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/message_freebsd_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/message_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/route.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/route_classic.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/route_openbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/route_test.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys_darwin.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys_dragonfly.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys_freebsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys_netbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/sys_openbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/syscall.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/syscall.s [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_darwin.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_dragonfly.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_freebsd_386.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_netbsd.go [new file with mode: 0644]
src/vendor/golang.org/x/net/route/zsys_openbsd.go [new file with mode: 0644]
test/fixedbugs/bug398.go
test/fixedbugs/issue13779.go
test/fixedbugs/issue14136.go [new file with mode: 0644]
test/fixedbugs/issue15277.go [new file with mode: 0644]
test/fixedbugs/issue15329.go [new file with mode: 0644]
test/fixedbugs/issue15548.dir/c.go
test/fixedbugs/issue15572.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue15572.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue15572.go [new file with mode: 0644]
test/fixedbugs/issue15585.go [new file with mode: 0644]
test/fixedbugs/issue15602.go [new file with mode: 0644]
test/fixedbugs/issue15604.go [new file with mode: 0644]
test/fixedbugs/issue15646.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue15646.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue15646.go [new file with mode: 0644]
test/fixedbugs/issue15733.go [new file with mode: 0644]
test/fixedbugs/issue15747.go [new file with mode: 0644]
test/fixedbugs/issue15747b.go [new file with mode: 0644]
test/fixedbugs/issue15838.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue15838.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue15838.go [new file with mode: 0644]
test/linkobj.go [new file with mode: 0644]

index 6851e147d338773bb39bf0c3b1cada656bb2450f..7173067a759c6f002a8e25510511d2e842c4dddb 100644 (file)
@@ -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/AUTHORS b/AUTHORS
index 34a78e5bd086358ec20cab43154c84db8e7b016b..d6b72718bcc4adf0eabd9eb392c073b6a25b241a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,13 +14,17 @@ A Medium Corporation
 Aamir Khan <syst3m.w0rm@gmail.com>
 Aaron France <aaron.l.france@gmail.com>
 Aaron Torres <tcboox@gmail.com>
+Abe Haskins <abeisgreat@abeisgreat.com>
 Abhinav Gupta <abhinav.g90@gmail.com>
 Adrian Nos <nos.adrian@gmail.com>
 Adrian O'Grady <elpollouk@gmail.com>
 Adrien Bustany <adrien-xx-google@bustany.org>
 Aécio Júnior <aeciodantasjunior@gmail.com>
 Ahmed Waheed Moanes <oneofone@gmail.com>
+Ahmy Yulrizka <yulrizka@gmail.com>
+Aiden Scandella <ai@uber.com>
 Ainar Garipov <gugl.zadolbal@gmail.com>
+Akihiro Suda <suda.kyoto@gmail.com>
 Akshat Kumar <seed@mail.nanosouffle.net>
 Alan Shreve <alan@inconshreveable.com>
 Albert Strasheim <fullung@gmail.com>
@@ -28,6 +32,7 @@ Alberto Bertogli <albertito@blitiri.com.ar>
 Alberto Donizetti <alb.donizetti@gmail.com>
 Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
 Aleksandar Dezelin <dezelin@gmail.com>
+Alessandro Arzilli <alessandro.arzilli@gmail.com>
 Alex A Skinner <alex@lx.lc>
 Alex Brainman <alex.brainman@gmail.com>
 Alex Jin <toalexjin@gmail.com>
@@ -50,8 +55,10 @@ Alexey Borzenkov <snaury@gmail.com>
 Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
 Aliaksandr Valialkin <valyala@gmail.com>
 Alif Rachmawadi <subosito@gmail.com>
+Amazon.com, Inc
 Amir Mohammad Saied <amir@gluegadget.com>
 Amrut Joshi <amrut.joshi@gmail.com>
+Andre Nathan <andrenth@gmail.com>
 Andrei Korzhevskii <a.korzhevskiy@gmail.com>
 Andrei Vieru <euvieru@gmail.com>
 Andrew Balholm <andybalholm@gmail.com>
@@ -85,6 +92,8 @@ Anthony Starks <ajstarks@gmail.com>
 Apisak Darakananda <pongad@gmail.com>
 Aram Hăvărneanu <aram@mgk.ro>
 Areski Belaid <areski@gmail.com>
+Arlo Breault <arlolra@gmail.com>
+ARM Ltd.
 Arnaud Ysmal <arnaud.ysmal@gmail.com>
 Arne Hormann <arnehormann@gmail.com>
 Arnout Engelen <arnout@bzzt.net>
@@ -92,6 +101,8 @@ Aron Nopanen <aron.nopanen@gmail.com>
 Artyom Pervukhin <artyom.pervukhin@gmail.com>
 Arvindh Rajesh Tamilmani <art@a-30.net>
 Ato Araki <ato.araki@gmail.com>
+Audrey Lim <audreylh@gmail.com>
+Augusto Roman <aroman@gmail.com>
 Aulus Egnatius Varialus <varialus@gmail.com>
 awaw fumin <awawfumin@gmail.com>
 Aymerick Jéhanne <aymerick@jehanne.org>
@@ -107,6 +118,8 @@ Bjorn Tipling <bjorn.tipling@gmail.com>
 Blake Gentry <blakesgentry@gmail.com>
 Blake Mizerany <blake.mizerany@gmail.com>
 Bobby Powers <bobbypowers@gmail.com>
+Brady Catherman <brady@gmail.com>
+Brady Sullivan <brady@bsull.com>
 Brendan Daniel Tracey <tracey.brendan@gmail.com>
 Brett Cannon <bcannon@gmail.com>
 Brian Dellisanti <briandellisanti@gmail.com>
@@ -140,17 +153,21 @@ Christoffer Buchholz <christoffer.buchholz@gmail.com>
 Christoph Hack <christoph@tux21b.org>
 Christopher Cahoon <chris.cahoon@gmail.com>
 Christopher Guiney <chris@guiney.net>
+Christopher Nelson <nadiasvertex@gmail.com>
 Christopher Nielsen <m4dh4tt3r@gmail.com>
 Christopher Redden <christopher.redden@gmail.com>
 Christopher Wedgwood <cw@f00f.org>
 CL Sung <clsung@gmail.com> <cl_sung@htc.com>
 Clement Skau <clementskau@gmail.com>
 CloudFlare Inc.
+Colin Edwards <colin@recursivepenguin.com>
 Colin Kennedy <moshen.colin@gmail.com>
+Conrad Irwin <conrad.irwin@gmail.com>
 Conrad Meyer <cemeyer@cs.washington.edu>
 CoreOS, Inc.
 Corey Thomasson <cthom.lists@gmail.com>
 Cristian Staretu <unclejacksons@gmail.com>
+Currant
 Damian Gryski <dgryski@gmail.com>
 Dan Caddigan <goldcaddy77@gmail.com>
 Dan Callahan <dan.callahan@gmail.com>
@@ -164,9 +181,12 @@ Daniel Lidén <daniel.liden.87@gmail.com>
 Daniel Morsing <daniel.morsing@gmail.com>
 Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
 Daniel Skinner <daniel@dasa.cc>
+Daniel Speichert <daniel@speichert.pl>
 Daniel Theophanes <kardianos@gmail.com>
 Darren Elwood <darren@textnode.com>
+Datong Sun <dndx@idndx.com>
 Dave Cheney <dave@cheney.net>
+David Brophy <dave@brophy.uk>
 David Bürgin <676c7473@gmail.com>
 David Calavera <david.calavera@gmail.com>
 David du Colombier <0intro@gmail.com>
@@ -176,21 +196,26 @@ David Howden <dhowden@gmail.com>
 David Jakob Fritz <david.jakob.fritz@gmail.com>
 David Leon Gil <coruus@gmail.com>
 David R. Jenni <david.r.jenni@gmail.com>
+David Sansome <me@davidsansome.com>
 David Thomas <davidthomas426@gmail.com>
 David Titarenco <david.titarenco@gmail.com>
 Davies Liu <davies.liu@gmail.com>
 Dean Prichard <dean.prichard@gmail.com>
 Denis Bernard <db047h@gmail.com>
 Denis Brandolini <denis.brandolini@gmail.com>
+Denys Honsiorovskyi <honsiorovskyi@gmail.com>
 Derek Buitenhuis <derek.buitenhuis@gmail.com>
 Derek Parker <parkerderek86@gmail.com>
+Derek Shockey <derek.shockey@gmail.com>
 Develer SRL
 Devon H. O'Dell <devon.odell@gmail.com>
 Dhiru Kholia <dhiru.kholia@gmail.com>
 Didier Spezia <didier.06@gmail.com>
 Dimitri Tcaciuc <dtcaciuc@gmail.com>
 Dirk Gadsden <dirk@esherido.com>
+Diwaker Gupta <diwakergupta@gmail.com>
 Dmitri Shuralyov <shurcooL@gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
 Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
 Dmitry Chestnykh <dchest@gmail.com>
 Dmitry Savintsev <dsavints@gmail.com>
@@ -200,6 +225,7 @@ Donald Huang <don.hcd@gmail.com>
 Donovan Hide <donovanhide@gmail.com>
 Dropbox, Inc.
 Duncan Holm <mail@frou.org>
+Dustin Herbison <djherbis@gmail.com>
 Dustin Sallings <dsallings@gmail.com>
 Dustin Shields-Cloues <dcloues@gmail.com>
 Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
@@ -220,6 +246,7 @@ Erik Aigner <aigner.erik@gmail.com>
 Erik Dubbelboer <erik@dubbelboer.com>
 Erik St. Martin <alakriti@gmail.com>
 Erik Westrup <erik.westrup@gmail.com>
+Ernest Chiang <ernest_chiang@htc.com>
 Esko Luontola <esko.luontola@gmail.com>
 Evan Phoenix <evan@phx.io>
 Evan Shaw <chickencha@gmail.com>
@@ -241,6 +268,7 @@ Francisco Souza <franciscossouza@gmail.com>
 Frederick Kelly Mayle III <frederickmayle@gmail.com>
 Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
 Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
+Frits van Bommel <fvbommel@gmail.com>
 Gabriel Aszalos <gabriel.aszalos@gmail.com>
 Gary Burd <gary@beagledreams.com>
 Gaurish Sharma <contact@gaurishsharma.com>
@@ -266,30 +294,37 @@ Hajime Hoshi <hajimehoshi@gmail.com>
 Hari haran <hariharan.uno@gmail.com>
 Hariharan Srinath <srinathh@gmail.com>
 Harley Laue <losinggeneration@gmail.com>
+Harshavardhana <hrshvardhana@gmail.com>
 Håvard Haugen <havard.haugen@gmail.com>
 Hector Chu <hectorchu@gmail.com>
 Hector Martin Cantero <hector@marcansoft.com>
 Henning Schmiedehausen <henning@schmiedehausen.org>
 Henrik Edwards <henrik.edwards@gmail.com>
 Herbert Georg Fischer <herbert.fischer@gmail.com>
+Hironao OTSUBO <motemen@gmail.com>
 Hiroshi Ioka <hirochachacha@gmail.com>
+Hitoshi Mitake <mitake.hitoshi@gmail.com>
+Holden Huang <ttyh061@gmail.com>
 Hong Ruiqi <hongruiqi@gmail.com>
 Hsin-Ho Yeh <yhh92u@gmail.com>
 Hu Keping <hukeping@huawei.com>
 Ian Gudger <ian@loosescre.ws>
 IBM
 Icarus Sparry <golang@icarus.freeuk.com>
+Idora Shinatose <idora.shinatose@gmail.com>
 Igneous Systems, Inc.
 Igor Dolzhikov <bluesriverz@gmail.com>
 INADA Naoki <songofacandy@gmail.com>
 Ingo Krabbe <ikrabbe.ask@gmail.com>
 Ingo Oeser <nightlyone@googlemail.com>
 Intel Corporation
+Irieda Noboru <irieda@gmail.com>
 Isaac Wagner <ibw@isaacwagner.me>
 Ivan Ukhov <ivan.ukhov@gmail.com>
 Jae Kwon <jae@tendermint.com>
 Jakob Borg <jakob@nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
+James Bardin <j.bardin@gmail.com>
 James David Chalfant <james.chalfant@gmail.com>
 James Fysh <james.fysh@gmail.com>
 James Gray <james@james4k.com>
@@ -299,6 +334,7 @@ James Schofield <james@shoeboxapp.com>
 James Sweet <james.sweet88@googlemail.com>
 James Toy <nil@opensesame.st>
 James Whitehead <jnwhiteh@gmail.com>
+Jamil Djadala <djadala@gmail.com>
 Jan H. Hosang <jan.hosang@gmail.com>
 Jan Mercl <0xjnml@gmail.com>
 Jan Mercl <befelemepeseveze@gmail.com>
@@ -315,6 +351,7 @@ Jeff Sickel <jas@corpus-callosum.com>
 Jeff Wendling <jeff@spacemonkey.com>
 Jens Frederich <jfrederich@gmail.com>
 Jeremy Jackins <jeremyjackins@gmail.com>
+Jess Frazelle <me@jessfraz.com>
 Jihyun Yu <yjh0502@gmail.com>
 Jim McGrath <jimmc2@gmail.com>
 Jimmy Zelinskie <jimmyzelinskie@gmail.com>
@@ -323,16 +360,21 @@ Jingguo Yao <yaojingguo@gmail.com>
 Jiong Du <londevil@gmail.com>
 Joakim Sernbrant <serbaut@gmail.com>
 Joe Harrison <joehazzers@gmail.com>
+Joe Henke <joed.henke@gmail.com>
 Joe Poirier <jdpoirier@gmail.com>
 Joe Shaw <joe@joeshaw.org>
+Joe Sylve <joe.sylve@gmail.com>
 Joe Tsai <joetsai@digital-static.net>
 Joel Stemmer <stemmertech@gmail.com>
+Johan Sageryd <j@1616.se>
 John Asmuth <jasmuth@gmail.com>
 John C Barstow <jbowtie@amathaine.com>
 John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
 John Howard Palevich <jack.palevich@gmail.com>
+John Jeffery <jjeffery@sp.com.au>
 John Jenkins <twodopeshaggy@gmail.com>
 John Potocny <johnp@vividcortex.com>
+John Schnake <schnake.john@gmail.com>
 John Shahid <jvshahid@gmail.com>
 John Tuley <john@tuley.org>
 Jonathan Boulle <jonathanboulle@gmail.com>
@@ -366,8 +408,13 @@ Kelvin Foo Chuan Lyi <vmirage@gmail.com>
 Ken Friedenbach <kenliz@cruzio.com>
 Ken Rockot <ken@oz.gs>
 Ken Sedgwick <ken@bonsai.com>
+Kenji Kaneda <kenji.kaneda@gmail.com>
+Kenneth Shaw <kenshaw@gmail.com>
 Kenny Grant <kennygrant@gmail.com>
 Kevin Ballard <kevin@sb.org>
+Kevin Burke <kev@inburke.com>
+Kevin Kirsche <kev.kirsche@gmail.com>
+Kevin Vu <kevin.m.vu@gmail.com>
 Klaus Post <klauspost@gmail.com>
 Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
 KPCompass, Inc.
@@ -379,12 +426,14 @@ Kyle Lemons <kyle@kylelemons.net>
 L Campbell <unpantsu@gmail.com>
 Lai Jiangshan <eag0628@gmail.com>
 Larz Conwell <larzconwell@gmail.com>
+Lee Hinman <hinman@gmail.com>
 Lee Packham <lpackham@gmail.com>
 Lewin Bormann <lewin.bormann@gmail.com>
 Liberty Fund Inc
 Linaro Limited
 Lloyd Dewolf <foolswisdom@gmail.com>
 Lorenzo Stoakes <lstoakes@gmail.com>
+Luan Santos <cfcluan@gmail.com>
 Luca Greco <luca.greco@alcacoop.it>
 Lucien Stuker <lucien.stuker@gmail.com>
 Lucio De Re <lucio.dere@gmail.com>
@@ -397,6 +446,7 @@ Manuel Mendez <mmendez534@gmail.com>
 Marc Weistroff <marc@weistroff.net>
 Marco Hennings <marco.hennings@freiheit.com>
 Mark Bucciarelli <mkbucc@gmail.com>
+Mark Severson <miquella@gmail.com>
 Mark Theunissen <mark.theunissen@gmail.com>
 Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
 Marko Tiikkaja <marko@joh.to>
@@ -404,12 +454,14 @@ Markover Inc. DBA Poptip
 Markus Duft <markus.duft@salomon.at>
 Markus Sonderegger <marraison@gmail.com>
 Markus Zimmermann <zimmski@gmail.com>
+Martin Garton <garton@gmail.com>
 Martin Möhrmann <martisch@uos.de>
 Martin Neubauer <m.ne@gmx.net>
 Martin Olsson <martin@minimum.se>
 Marvin Stenger <marvin.stenger94@gmail.com>
 Mateusz Czapliński <czapkofan@gmail.com>
 Mathias Beke <git@denbeke.be>
+Mathias Leppich <mleppich@muhqu.de>
 Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
 Mats Lidell <mats.lidell@cag.se>
 Matt Aimonetti <mattaimonetti@gmail.com>
@@ -419,6 +471,7 @@ Matt Jibson <matt.jibson@gmail.com>
 Matt Joiner <anacrolix@gmail.com>
 Matt Layher <mdlayher@gmail.com>
 Matt Reiferson <mreiferson@gmail.com>
+Matt Robenolt <matt@ydekproductions.com>
 Matt T. Proud <matt.proud@gmail.com>
 Matt Williams <gh@mattyw.net>
 Matthew Brennan <matty.brennan@gmail.com>
@@ -426,6 +479,7 @@ Matthew Cottingham <mattcottingham@gmail.com>
 Matthew Holt <Matthew.Holt+git@gmail.com>
 Matthew Horsnell <matthew.horsnell@gmail.com>
 Maxim Khitrov <max@mxcrypt.com>
+Maxwell Krohn <themax@gmail.com>
 Meir Fischer <meirfischer@gmail.com>
 Meng Zhuo <mengzhuo1203@gmail.com>
 Meteor Development Group
@@ -439,6 +493,7 @@ Michael Hoisie <hoisie@gmail.com>
 Michael Käufl <golang@c.michael-kaeufl.de>
 Michael Lewis <mikelikespie@gmail.com>
 Michael MacInnis <Michael.P.MacInnis@gmail.com>
+Michael McConville <momcconville@gmail.com>
 Michael Pearson <mipearson@gmail.com>
 Michael Schaller <michael@5challer.de>
 Michael Stapelberg <michael@stapelberg.de>
@@ -451,15 +506,19 @@ Mihai Borobocea <MihaiBorobocea@gmail.com>
 Mikael Tillenius <mikti42@gmail.com>
 Mike Andrews <mra@xoba.com>
 Mike Rosset <mike.rosset@gmail.com>
+Mikhail Gusarov <dottedmag@dottedmag.net>
 Mikhail Panchenko <m@mihasya.com>
 Miki Tebeka <miki.tebeka@gmail.com>
 Mikio Hara <mikioh.mikioh@gmail.com>
 Mikkel Krautz <mikkel@krautz.dk>
 Miquel Sabaté Solà <mikisabate@gmail.com>
 Mohit Agarwal <mohit@sdf.org>
+Monty Taylor <mordred@inaugust.com>
 Moov Corporation
 Moriyoshi Koizumi <mozo@mozo.jp>
+Morten Siebuhr <sbhr@sbhr.dk>
 Môshe van der Sterre <moshevds@gmail.com>
+Muhammed Uluyol <uluyol0@gmail.com>
 Nan Deng <monnand@gmail.com>
 Nathan John Youngman <nj@nathany.com>
 Nathan Otterness <otternes@cs.unc.edu>
@@ -467,17 +526,23 @@ Nathan P Finch <nate.finch@gmail.com>
 Nathan VanBenschoten <nvanbenschoten@gmail.com>
 Nathan Youngman <git@nathany.com>
 Neelesh Chandola <neelesh.c98@gmail.com>
+Netflix, Inc.
 Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
 ngmoco, LLC
+Niall Sheridan <nsheridan@gmail.com>
 Nicholas Katsaros <nick@nickkatsaros.com>
 Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
 Nicholas Sullivan <nicholas.sullivan@gmail.com>
 Nicholas Waples <nwaples@gmail.com>
 Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
+Nick Patavalis <nick.patavalis@gmail.com>
+Nick Petroni <npetroni@cs.umd.edu>
 Nicolas Kaiser <nikai@nikai.net>
 Nicolas Owens <mischief@offblast.org>
 Nicolas S. Dade <nic.dade@gmail.com>
+Niels Widger <niels.widger@gmail.com>
 Nigel Kerr <nigel.kerr@gmail.com>
+Niko Dziemba <niko@dziemba.com>
 Nikolay Turpitko <nikolay@turpitko.com>
 Noah Campbell <noahcampbell@gmail.com>
 Norberto Lopes <nlopes.ml@gmail.com>
@@ -486,8 +551,11 @@ Oling Cat <olingcat@gmail.com>
 Oliver Hookins <ohookins@gmail.com>
 Olivier Antoine <olivier.antoine@gmail.com>
 Olivier Duperray <duperray.olivier@gmail.com>
+Olivier Poitrey <rs@dailymotion.com>
 Olivier Saingre <osaingre@gmail.com>
 Oracle
+Orange
+Özgür Kesim <oec-go@kesim.org>
 Padraig Kitterick <padraigkitterick@gmail.com>
 Palm Stone Games
 Paolo Giarrusso <p.giarrusso@gmail.com>
@@ -523,10 +591,13 @@ Péter Szilágyi <peterke@gmail.com>
 Peter Waldschmidt <peter@waldschmidt.com>
 Peter Waller <peter.waller@gmail.com>
 Peter Williams <pwil3058@gmail.com>
+Philip Hofer <phofer@umich.edu>
 Philip K. Warren <pkwarren@gmail.com>
+Pierre Durand <pierredurand@gmail.com>
 Pierre Roullon <pierre.roullon@gmail.com>
 Pieter Droogendijk <pieter@binky.org.uk>
 Pietro Gagliardi <pietro10@mac.com>
+Prashant Varanasi <prashant@prashantv.com>
 Preetam Jinka <pj@preet.am>
 Quan Yong Zhai <qyzhai@gmail.com>
 Quentin Perez <qperez@ocs.online.net>
@@ -538,9 +609,11 @@ Ralph Corderoy <ralph@inputplus.co.uk>
 Red Hat, Inc.
 Reinaldo de Souza Jr <juniorz@gmail.com>
 Rémy Oudompheng <oudomphe@phare.normalesup.org>
+Ricardo Padilha <ricardospadilha@gmail.com>
 Richard Barnes <rlb@ipv.sx>
 Richard Crowley <r@rcrowley.org>
 Richard Eric Gavaletz <gavaletz@gmail.com>
+Richard Miller <miller.research@gmail.com>
 Richard Musiol <mail@richard-musiol.de>
 Rick Arnold <rickarnoldjr@gmail.com>
 Risto Jaakko Saarelma <rsaarelm@gmail.com>
@@ -556,6 +629,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
 Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
 Roger Pau Monné <royger@gmail.com>
 Roger Peppe <rogpeppe@gmail.com>
+Roland Shoemaker <rolandshoemaker@gmail.com>
 Ron Hashimoto <mail@h2so5.net>
 Ron Minnich <rminnich@gmail.com>
 Ross Light <rlight2@gmail.com>
@@ -567,8 +641,11 @@ Ryan Seys <ryan@ryanseys.com>
 Ryan Slade <ryanslade@gmail.com>
 S.Çağlar Onur <caglar@10ur.org>
 Salmān Aljammāz <s@0x65.net>
+Sam Hug <samuel.b.hug@gmail.com>
+Sam Whited <sam@samwhited.com>
 Sanjay Menakuru <balasanjay@gmail.com>
 Scott Barron <scott.barron@github.com>
+Scott Bell <scott@sctsm.com>
 Scott Ferguson <scottwferg@gmail.com>
 Scott Lawrence <bytbox@gmail.com>
 Sebastien Binet <seb.binet@gmail.com>
@@ -577,17 +654,21 @@ Sergei Skorobogatov <skorobo@rambler.ru>
 Sergey 'SnakE'  Gromov <snake.scaly@gmail.com>
 Sergio Luis O. B. Correia <sergio@correia.cc>
 Seth Hoenig <seth.a.hoenig@gmail.com>
+Shahar Kohanim <skohanim@gmail.com>
 Shane Hansen <shanemhansen@gmail.com>
 Shaozhen Ding <dsz0111@gmail.com>
 Shawn Smith <shawn.p.smith@gmail.com>
 Shenghou Ma <minux.ma@gmail.com>
+Shinji Tanaka <shinji.tanaka@gmail.com>
 Shivakumar GN <shivakumar.gn@gmail.com>
 Silvan Jegen <s.jegen@gmail.com>
+Simon Jefford <simon.jefford@gmail.com>
 Simon Whitehead <chemnova@gmail.com>
 Sokolov Yura <funny.falcon@gmail.com>
 Spencer Nelson <s@spenczar.com>
 Spring Mc <heresy.mc@gmail.com>
 Square, Inc.
+Sridhar Venkatakrishnan <sridhar@laddoo.net>
 StalkR <stalkr@stalkr.net>
 Stan Schwertly <stan@schwertly.com>
 Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
@@ -605,6 +686,7 @@ Szabolcs Nagy <nsz@port70.net>
 Tad Glines <tad.glines@gmail.com>
 Taj Khattra <taj.khattra@gmail.com>
 Takeshi YAMANASHI <9.nashi@gmail.com>
+Tal Shprecher <tshprecher@gmail.com>
 Tamir Duberstein <tamird@gmail.com>
 Tarmigan Casebolt <tarmigan@gmail.com>
 Taru Karttunen <taruti@taruti.net>
@@ -615,9 +697,12 @@ Thomas Alan Copeland <talan.copeland@gmail.com>
 Thomas Desrosiers <thomasdesr@gmail.com>
 Thomas Kappler <tkappler@gmail.com>
 Thorben Krueger <thorben.krueger@gmail.com>
+Tilman Dilo <tilman.dilo@gmail.com>
 Tim Cooijmans <timcooijmans@gmail.com>
+Tim Ebringer <tim.ebringer@gmail.com>
 Timo Savola <timo.savola@gmail.com>
 Timo Truyts <alkaloid.btx@gmail.com>
+Timothy Studd <tim@timstudd.com>
 Tobias Columbus <tobias.columbus@gmail.com>
 Todd Neal <todd@tneal.org>
 Tom Heng <zhm20070928@gmail.com>
@@ -634,12 +719,15 @@ Tyler Treat <ttreat31@gmail.com>
 Ugorji Nwoke <ugorji@gmail.com>
 Ulf Holm Nielsen <doktor@dyregod.dk>
 Ulrich Kunitz <uli.kunitz@gmail.com>
+Upthere, Inc.
 Uriel Mangado <uriel@berlinblue.org>
+Vadim Grek <vadimprog@gmail.com>
 Vadim Vygonets <unixdj@gmail.com>
 Vincent Ambo <tazjin@googlemail.com>
 Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
 Vincent Vanackere <vincent.vanackere@gmail.com>
 Vinu Rajashekhar <vinutheraj@gmail.com>
+Vishvananda Ishaya <vishvananda@gmail.com>
 Vladimir Nikishenko <vova616@gmail.com>
 Volker Dobler <dr.volker.dobler@gmail.com>
 Wei Guangjing <vcc.163@gmail.com>
@@ -648,6 +736,7 @@ William Josephson <wjosephson@gmail.com>
 William Orr <will@worrbase.com> <ay1244@gmail.com>
 Xia Bin <snyh@snyh.org>
 Xing Xing <mikespook@gmail.com>
+Xudong Zhang <felixmelon@gmail.com>
 Yahoo Inc.
 Yann Kerhervé <yann.kerherve@gmail.com>
 Yao Zhang <lunaria21@gmail.com>
@@ -661,6 +750,7 @@ Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats@gmail.com>
 Yuusei Kuwana <kuwana@kumama.org>
 Yuval Pavel Zholkover <paulzhol@gmail.com>
+Zemanta d.o.o.
 Ziad Hatahet <hatahet@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
 申习之 <bronze1man@gmail.com>
index e225afec80c6ee1ce0ca50901e7984d0c91f4f18..6845a392680b614ef8e263e3fa31ac3daf69788b 100644 (file)
@@ -37,6 +37,7 @@ Aaron France <aaron.l.france@gmail.com>
 Aaron Jacobs <jacobsa@google.com>
 Aaron Kemp <kemp.aaron@gmail.com>
 Aaron Torres <tcboox@gmail.com>
+Abe Haskins <abeisgreat@abeisgreat.com>
 Abhinav Gupta <abhinav.g90@gmail.com>
 Adam Langley <agl@golang.org>
 Adrian Nos <nos.adrian@gmail.com>
@@ -44,7 +45,10 @@ Adrian O'Grady <elpollouk@gmail.com>
 Adrien Bustany <adrien-xx-google@bustany.org>
 Aécio Júnior <aeciodantasjunior@gmail.com>
 Ahmed Waheed Moanes <oneofone@gmail.com>
+Ahmy Yulrizka <yulrizka@gmail.com>
+Aiden Scandella <ai@uber.com>
 Ainar Garipov <gugl.zadolbal@gmail.com>
+Akihiro Suda <suda.kyoto@gmail.com>
 Akshat Kumar <seed@mail.nanosouffle.net>
 Alan Donovan <adonovan@google.com>
 Alan Shreve <alan@inconshreveable.com>
@@ -53,6 +57,7 @@ Alberto Bertogli <albertito@blitiri.com.ar>
 Alberto Donizetti <alb.donizetti@gmail.com>
 Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
 Aleksandar Dezelin <dezelin@gmail.com>
+Alessandro Arzilli <alessandro.arzilli@gmail.com>
 Alex A Skinner <alex@lx.lc>
 Alex Brainman <alex.brainman@gmail.com>
 Alex Bramley <abramley@google.com>
@@ -60,6 +65,7 @@ Alex Jin <toalexjin@gmail.com>
 Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
 Alex Schroeder <alex@gnu.org>
 Alex Sergeyev <abc@alexsergeyev.com>
+Alex Vaghin <crhyme@google.com>
 Alexander Demakin <alexander.demakin@gmail.com>
 Alexander Larsson <alexander.larsson@gmail.com>
 Alexander Morozov <lk4d4math@gmail.com>
@@ -80,6 +86,7 @@ Aliaksandr Valialkin <valyala@gmail.com>
 Alif Rachmawadi <subosito@gmail.com>
 Amir Mohammad Saied <amir@gluegadget.com>
 Amrut Joshi <amrut.joshi@gmail.com>
+Andre Nathan <andrenth@gmail.com>
 Andrea Spadaccini <spadaccio@google.com>
 Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
 Andrei Korzhevskii <a.korzhevskiy@gmail.com>
@@ -98,6 +105,7 @@ Andrew Pritchard <awpritchard@gmail.com>
 Andrew Radev <andrey.radev@gmail.com>
 Andrew Skiba <skibaa@gmail.com>
 Andrew Szeto <andrew@jabagawee.com>
+Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
 Andrew Wilkins <axwalk@gmail.com>
 Andrew Williams <williams.andrew@gmail.com>
 Andrey Mirtchovski <mirtchovski@gmail.com>
@@ -119,6 +127,7 @@ Apisak Darakananda <pongad@gmail.com>
 Aram Hăvărneanu <aram@mgk.ro>
 Areski Belaid <areski@gmail.com>
 Arkadi Pyuro <arkadi@google.com>
+Arlo Breault <arlolra@gmail.com>
 Arnaud Ysmal <arnaud.ysmal@gmail.com>
 Arne Hormann <arnehormann@gmail.com>
 Arnout Engelen <arnout@bzzt.net>
@@ -127,6 +136,8 @@ Artyom Pervukhin <artyom.pervukhin@gmail.com>
 Arvindh Rajesh Tamilmani <art@a-30.net>
 Asim Shankar <asimshankar@gmail.com>
 Ato Araki <ato.araki@gmail.com>
+Audrey Lim <audreylh@gmail.com>
+Augusto Roman <aroman@gmail.com>
 Aulus Egnatius Varialus <varialus@gmail.com>
 Austin Clements <austin@google.com> <aclements@csail.mit.edu>
 awaw fumin <awawfumin@gmail.com>
@@ -139,6 +150,7 @@ Ben Lynn <benlynn@gmail.com>
 Ben Olive <sionide21@gmail.com>
 Benjamin Black <b@b3k.us>
 Benjamin Prosnitz <bprosnitz@google.com>
+Benjamin Wester <bwester@squareup.com>
 Benny Siegert <bsiegert@gmail.com>
 Benoit Sigoure <tsunanet@gmail.com>
 Berengar Lehr <Berengar.Lehr@gmx.de>
@@ -152,6 +164,8 @@ Blake Mizerany <blake.mizerany@gmail.com>
 Bobby Powers <bobbypowers@gmail.com>
 Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
 Brad Garcia <bgarcia@golang.org>
+Brady Catherman <brady@gmail.com>
+Brady Sullivan <brady@bsull.com>
 Brandon Gilmore <varz@google.com>
 Brendan Daniel Tracey <tracey.brendan@gmail.com>
 Brendan O'Dea <bod@golang.org>
@@ -163,8 +177,10 @@ Brian Ketelsen <bketelsen@gmail.com>
 Brian Slesinsky <skybrian@google.com>
 Brian Smith <ohohvi@gmail.com>
 Bryan C. Mills <bcmills@google.com>
+Bryan Chan <bryan.chan@ca.ibm.com>
 Bryan Ford <brynosaurus@gmail.com>
 Caine Tighe <arctanofyourface@gmail.com>
+Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
 Caleb Spare <cespare@gmail.com>
 Carl Chatfield <carlchatfield@gmail.com>
 Carl Jackson <carl@stripe.com>
@@ -175,6 +191,7 @@ Carlos Cirello <uldericofilho@gmail.com>
 Cary Hull <chull@google.com>
 Case Nelson <case.nelson@gmail.com>
 Casey Marshall <casey.marshall@gmail.com>
+Catalin Nicutar <cnicutar@google.com>
 Catalin Patulea <catalinp@google.com>
 Cedric Staub <cs@squareup.com>
 Cezar Sá Espinola <cezarsa@gmail.com>
@@ -182,6 +199,7 @@ ChaiShushan <chaishushan@gmail.com>
 Charles L. Dorian <cldorian@gmail.com>
 Charles Lee <zombie.fml@gmail.com>
 Charles Weill <weill@google.com>
+Cherry Zhang <cherryyz@google.com>
 Chris Broadfoot <cbro@golang.org>
 Chris Dollin <ehog.hedge@gmail.com>
 Chris Farmiloe <chrisfarms@gmail.com>
@@ -193,25 +211,31 @@ Chris Kastorff <encryptio@gmail.com>
 Chris Lennert <calennert@gmail.com>
 Chris Manghane <cmang@golang.org>
 Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
+Chris Zou <chriszou@ca.ibm.com>
 Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
 Christine Hansmann <chhansmann@gmail.com>
 Christoffer Buchholz <christoffer.buchholz@gmail.com>
 Christoph Hack <christoph@tux21b.org>
 Christopher Cahoon <chris.cahoon@gmail.com>
 Christopher Guiney <chris@guiney.net>
+Christopher Nelson <nadiasvertex@gmail.com>
 Christopher Nielsen <m4dh4tt3r@gmail.com>
 Christopher Redden <christopher.redden@gmail.com>
 Christopher Swenson <cswenson@google.com>
 Christopher Wedgwood <cw@f00f.org>
+Christy Perez <christy@linux.vnet.ibm.com>
 CL Sung <clsung@gmail.com> <cl_sung@htc.com>
 Clement Skau <clementskau@gmail.com>
 Colby Ranger <cranger@google.com>
 Colin Cross <ccross@android.com>
+Colin Edwards <colin@recursivepenguin.com>
 Colin Kennedy <moshen.colin@gmail.com>
+Conrad Irwin <conrad.irwin@gmail.com>
 Conrad Meyer <cemeyer@cs.washington.edu>
 Corey Thomasson <cthom.lists@gmail.com>
 Cosmos Nicolaou <cnicolaou@google.com>
 Cristian Staretu <unclejacksons@gmail.com>
+Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
 Damian Gryski <dgryski@gmail.com>
 Damien Neil <dneil@google.com>
 Dan Caddigan <goldcaddy77@gmail.com>
@@ -229,8 +253,10 @@ Daniel Morsing <daniel.morsing@gmail.com>
 Daniel Nadasi <dnadasi@google.com>
 Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
 Daniel Skinner <daniel@dasa.cc>
+Daniel Speichert <daniel@speichert.pl>
 Daniel Theophanes <kardianos@gmail.com>
 Darren Elwood <darren@textnode.com>
+Datong Sun <dndx@idndx.com>
 Dave Borowitz <dborowitz@google.com>
 Dave Bort <dbort@golang.org>
 Dave Cheney <dave@cheney.net>
@@ -239,6 +265,7 @@ Dave Grijalva <dgrijalva@ngmoco.com>
 David Anderson <danderson@google.com>
 David Barnett <dbarnett@google.com>
 David Benjamin <davidben@google.com>
+David Brophy <dave@brophy.uk>
 David Bürgin <676c7473@gmail.com>
 David Calavera <david.calavera@gmail.com>
 David Chase <drchase@google.com>
@@ -254,6 +281,7 @@ David Leon Gil <coruus@gmail.com>
 David McLeish <davemc@google.com>
 David Presotto <presotto@gmail.com>
 David R. Jenni <david.r.jenni@gmail.com>
+David Sansome <me@davidsansome.com>
 David Symonds <dsymonds@golang.org>
 David Thomas <davidthomas426@gmail.com>
 David Titarenco <david.titarenco@gmail.com>
@@ -261,15 +289,19 @@ Davies Liu <davies.liu@gmail.com>
 Dean Prichard <dean.prichard@gmail.com>
 Denis Bernard <db047h@gmail.com>
 Denis Brandolini <denis.brandolini@gmail.com>
+Denys Honsiorovskyi <honsiorovskyi@gmail.com>
 Derek Buitenhuis <derek.buitenhuis@gmail.com>
 Derek Che <drc@yahoo-inc.com>
 Derek Parker <parkerderek86@gmail.com>
+Derek Shockey <derek.shockey@gmail.com>
 Devon H. O'Dell <devon.odell@gmail.com>
 Dhiru Kholia <dhiru.kholia@gmail.com>
 Didier Spezia <didier.06@gmail.com>
 Dimitri Tcaciuc <dtcaciuc@gmail.com>
 Dirk Gadsden <dirk@esherido.com>
+Diwaker Gupta <diwakergupta@gmail.com>
 Dmitri Shuralyov <shurcooL@gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
 Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
 Dmitriy Vyukov <dvyukov@google.com>
 Dmitry Chestnykh <dchest@gmail.com>
@@ -279,8 +311,11 @@ Dominik Honnef <dominik.honnef@gmail.com>
 Dominik Vogt <vogt@linux.vnet.ibm.com>
 Donald Huang <don.hcd@gmail.com>
 Donovan Hide <donovanhide@gmail.com>
+Doug Anderson <douga@google.com>
 Drew Hintz <adhintz@google.com>
 Duncan Holm <mail@frou.org>
+Dustin Carlino <dcarlino@google.com>
+Dustin Herbison <djherbis@gmail.com>
 Dustin Long <dustmop@gmail.com>
 Dustin Sallings <dsallings@gmail.com>
 Dustin Shields-Cloues <dcloues@gmail.com>
@@ -304,7 +339,9 @@ Erik Aigner <aigner.erik@gmail.com>
 Erik Dubbelboer <erik@dubbelboer.com>
 Erik St. Martin <alakriti@gmail.com>
 Erik Westrup <erik.westrup@gmail.com>
+Ernest Chiang <ernest_chiang@htc.com>
 Esko Luontola <esko.luontola@gmail.com>
+Ethan Burns <eaburns@google.com>
 Evan Broder <evan@stripe.com>
 Evan Brown <evanbrown@google.com>
 Evan Kroske <evankroske@google.com>
@@ -331,11 +368,13 @@ Francisco Souza <franciscossouza@gmail.com>
 Frederick Kelly Mayle III <frederickmayle@gmail.com>
 Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
 Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
+Frits van Bommel <fvbommel@gmail.com>
 Fumitoshi Ukai <ukai@google.com>
 Gaal Yahas <gaal@google.com>
 Gabriel Aszalos <gabriel.aszalos@gmail.com>
 Garrick Evans <garrick@google.com>
 Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
+Gary Elliott <garyelliott@google.com>
 Gaurish Sharma <contact@gaurishsharma.com>
 Gautham Thambidorai <gautham.dorai@gmail.com>
 Geert-Johan Riemer <gjr19912@gmail.com>
@@ -359,17 +398,22 @@ Gustavo Franco <gustavorfranco@gmail.com>
 Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
 Gwenael Treguier <gwenn.kahz@gmail.com>
 Hajime Hoshi <hajimehoshi@gmail.com>
+Hallgrimur Gunnarsson <halg@google.com>
 Han-Wen Nienhuys <hanwen@google.com>
 Hari haran <hariharan.uno@gmail.com>
 Hariharan Srinath <srinathh@gmail.com>
 Harley Laue <losinggeneration@gmail.com>
+Harshavardhana <hrshvardhana@gmail.com>
 Håvard Haugen <havard.haugen@gmail.com>
 Hector Chu <hectorchu@gmail.com>
 Hector Martin Cantero <hector@marcansoft.com>
 Henning Schmiedehausen <henning@schmiedehausen.org>
 Henrik Edwards <henrik.edwards@gmail.com>
 Herbert Georg Fischer <herbert.fischer@gmail.com>
+Hironao OTSUBO <motemen@gmail.com>
 Hiroshi Ioka <hirochachacha@gmail.com>
+Hitoshi Mitake <mitake.hitoshi@gmail.com>
+Holden Huang <ttyh061@gmail.com>
 Hong Ruiqi <hongruiqi@gmail.com>
 Hossein Sheikh Attar <hattar@google.com>
 Hsin-Ho Yeh <yhh92u@gmail.com>
@@ -378,11 +422,13 @@ Hyang-Ah Hana Kim <hakim@google.com> <hyangah@gmail.com>
 Ian Gudger <ian@loosescre.ws>
 Ian Lance Taylor <iant@golang.org>
 Icarus Sparry <golang@icarus.freeuk.com>
+Idora Shinatose <idora.shinatose@gmail.com>
 Igor Dolzhikov <bluesriverz@gmail.com>
 Ilya Tocar <ilya.tocar@intel.com>
 INADA Naoki <songofacandy@gmail.com>
 Ingo Krabbe <ikrabbe.ask@gmail.com>
 Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
+Irieda Noboru <irieda@gmail.com>
 Isaac Wagner <ibw@isaacwagner.me>
 Ivan Krasin <krasin@golang.org>
 Ivan Ukhov <ivan.ukhov@gmail.com>
@@ -394,6 +440,8 @@ Jakob Borg <jakob@nym.se>
 Jakub Čajka <jcajka@redhat.com>
 Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
 James Aguilar <jaguilar@google.com>
+James Bardin <j.bardin@gmail.com>
+James Chacon <jchacon@google.com>
 James David Chalfant <james.chalfant@gmail.com>
 James Fysh <james.fysh@gmail.com>
 James Gray <james@james4k.com>
@@ -408,6 +456,7 @@ James Whitehead <jnwhiteh@gmail.com>
 Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
 Jamie Turner <jamwt@dropbox.com>
 Jamie Wilkinson <jaq@spacepants.org>
+Jamil Djadala <djadala@gmail.com>
 Jan H. Hosang <jan.hosang@gmail.com>
 Jan Kratochvil <jan.kratochvil@redhat.com>
 Jan Mercl <0xjnml@gmail.com>
@@ -422,6 +471,7 @@ Jason Travis <infomaniac7@gmail.com>
 Jay Weisskopf <jay@jayschwa.net>
 Jean-Marc Eurin <jmeurin@google.com>
 Jed Denlea <jed@fastly.com>
+Jeff Craig <jeffcraig@google.com>
 Jeff Hodges <jeff@somethingsimilar.com>
 Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
 Jeff Sickel <jas@corpus-callosum.com>
@@ -430,6 +480,7 @@ Jens Frederich <jfrederich@gmail.com>
 Jeremiah Harmsen <jeremiah@google.com>
 Jeremy Jackins <jeremyjackins@gmail.com>
 Jeremy Schlatter <jeremy.schlatter@gmail.com>
+Jess Frazelle <me@jessfraz.com>
 Jihyun Yu <yjh0502@gmail.com>
 Jim Cote <jfcote87@gmail.com>
 Jim McGrath <jimmc2@gmail.com>
@@ -439,12 +490,15 @@ Jingguo Yao <yaojingguo@gmail.com>
 Jiong Du <londevil@gmail.com>
 Joakim Sernbrant <serbaut@gmail.com>
 Joe Harrison <joehazzers@gmail.com>
+Joe Henke <joed.henke@gmail.com>
 Joe Poirier <jdpoirier@gmail.com>
 Joe Shaw <joe@joeshaw.org>
+Joe Sylve <joe.sylve@gmail.com>
 Joe Tsai <joetsai@digital-static.net>
 Joel Sing <jsing@google.com>
 Joel Stemmer <stemmertech@gmail.com>
 Johan Euphrosine <proppy@google.com>
+Johan Sageryd <j@1616.se>
 John Asmuth <jasmuth@gmail.com>
 John Beisley <huin@google.com>
 John C Barstow <jbowtie@amathaine.com>
@@ -452,12 +506,15 @@ John DeNero <denero@google.com>
 John Dethridge <jcd@golang.org>
 John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
 John Howard Palevich <jack.palevich@gmail.com>
+John Jeffery <jjeffery@sp.com.au>
 John Jenkins <twodopeshaggy@gmail.com>
 John Newlin <jnewlin@google.com>
 John Potocny <johnp@vividcortex.com>
+John Schnake <schnake.john@gmail.com>
 John Shahid <jvshahid@gmail.com>
 John Tuley <john@tuley.org>
 Jonathan Allie <jonallie@google.com>
+Jonathan Amsterdam <jba@google.com>
 Jonathan Boulle <jonathanboulle@gmail.com>
 Jonathan Feinberg <feinberg@google.com>
 Jonathan Gold <jgold.bg@gmail.com>
@@ -481,11 +538,14 @@ Jostein Stuhaug <js@solidsystem.no>
 JP Sugarbroad <jpsugar@google.com>
 JT Olds <jtolds@xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka@gmail.com>
+Julia Hansbrough <flowerhack@google.com>
 Julian Phillips <julian@quantumfyre.co.uk>
 Julien Schmidt <google@julienschmidt.com>
 Jungho Ahn <jhahn@google.com>
+Jure Ham <jure.ham@zemanta.com>
 Justin Nuß <nuss.justin@gmail.com>
 Kai Backman <kaib@golang.org>
+Kamal Aboul-Hosn <aboulhosn@google.com>
 Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
 Kang Hu <hukangustc@gmail.com>
 Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
@@ -502,10 +562,15 @@ Ken Friedenbach <kenliz@cruzio.com>
 Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
 Ken Sedgwick <ken@bonsai.com>
 Ken Thompson <ken@golang.org>
+Kenji Kaneda <kenji.kaneda@gmail.com>
+Kenneth Shaw <kenshaw@gmail.com>
 Kenny Grant <kennygrant@gmail.com>
 Kevin Ballard <kevin@sb.org>
+Kevin Burke <kev@inburke.com>
+Kevin Kirsche <kev.kirsche@gmail.com>
 Kevin Klues <klueska@gmail.com> <klueska@google.com>
 Kevin Malachowski <chowski@google.com>
+Kevin Vu <kevin.m.vu@gmail.com>
 Kim Shrier <kshrier@racktopsystems.com>
 Kirklin McDonald <kirklin.mcdonald@gmail.com>
 Klaus Post <klauspost@gmail.com>
@@ -519,11 +584,13 @@ L Campbell <unpantsu@gmail.com>
 Lai Jiangshan <eag0628@gmail.com>
 Larry Hosken <lahosken@golang.org>
 Larz Conwell <larzconwell@gmail.com>
+Lee Hinman <hinman@gmail.com>
 Lee Packham <lpackham@gmail.com>
 Lewin Bormann <lewin.bormann@gmail.com>
 Lloyd Dewolf <foolswisdom@gmail.com>
 Lorenzo Stoakes <lstoakes@gmail.com>
 Louis Kruger <louisk@google.com>
+Luan Santos <cfcluan@gmail.com>
 Luca Greco <luca.greco@alcacoop.it>
 Lucien Stuker <lucien.stuker@gmail.com>
 Lucio De Re <lucio.dere@gmail.com>
@@ -539,11 +606,13 @@ Manu Garg <manugarg@google.com>
 Manu S Ajith <neo@codingarena.in>
 Manuel Mendez <mmendez534@gmail.com>
 Marc Weistroff <marc@weistroff.net>
+Marc-Antoine Ruel <maruel@chromium.org>
 Marcel van Lohuizen <mpvl@golang.org>
 Marco Hennings <marco.hennings@freiheit.com>
 Marga Manterola <marga@google.com>
 Marius Nuennerich <mnu@google.com>
 Mark Bucciarelli <mkbucc@gmail.com>
+Mark Severson <miquella@gmail.com>
 Mark Theunissen <mark.theunissen@gmail.com>
 Mark Zavislak <zavislak@google.com>
 Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
@@ -552,12 +621,14 @@ Marko Tiikkaja <marko@joh.to>
 Markus Duft <markus.duft@salomon.at>
 Markus Sonderegger <marraison@gmail.com>
 Markus Zimmermann <zimmski@gmail.com>
+Martin Garton <garton@gmail.com>
 Martin Möhrmann <martisch@uos.de>
 Martin Neubauer <m.ne@gmx.net>
 Martin Olsson <martin@minimum.se>
 Marvin Stenger <marvin.stenger94@gmail.com>
 Mateusz Czapliński <czapkofan@gmail.com>
 Mathias Beke <git@denbeke.be>
+Mathias Leppich <mleppich@muhqu.de>
 Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
 Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
 Matt Aimonetti <mattaimonetti@gmail.com>
@@ -569,6 +640,7 @@ Matt Joiner <anacrolix@gmail.com>
 Matt Jones <mrjones@google.com>
 Matt Layher <mdlayher@gmail.com>
 Matt Reiferson <mreiferson@gmail.com>
+Matt Robenolt <matt@ydekproductions.com>
 Matt T. Proud <matt.proud@gmail.com>
 Matt Williams <gh@mattyw.net> <mattyjwilliams@gmail.com>
 Matthew Brennan <matty.brennan@gmail.com>
@@ -579,6 +651,7 @@ Matthew Horsnell <matthew.horsnell@gmail.com>
 Maxim Khitrov <max@mxcrypt.com>
 Maxim Pimenov <mpimenov@google.com>
 Maxim Ushakov <ushakov@google.com>
+Maxwell Krohn <themax@gmail.com>
 Meir Fischer <meirfischer@gmail.com>
 Meng Zhuo <mengzhuo1203@gmail.com>
 Mhd Sulhan <m.shulhan@gmail.com>
@@ -595,9 +668,12 @@ Michael Lewis <mikelikespie@gmail.com>
 Michael MacInnis <Michael.P.MacInnis@gmail.com>
 Michael Marineau <michael.marineau@coreos.com>
 Michael Matloob <matloob@google.com>
+Michael McConville <momcconville@gmail.com>
 Michael McGreevy <mcgreevy@golang.org>
+Michael Munday <munday@ca.ibm.com>
 Michael Pearson <mipearson@gmail.com>
 Michael Piatek <piatek@google.com>
+Michael Pratt <mpratt@google.com>
 Michael Schaller <michael@5challer.de>
 Michael Shields <mshields@google.com>
 Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
@@ -608,22 +684,28 @@ Michal Bohuslávek <mbohuslavek@gmail.com>
 Michal Cierniak <cierniak@google.com>
 Michał Derkacz <ziutek@lnet.pl>
 Michalis Kargakis <michaliskargakis@gmail.com>
+Michel Lespinasse <walken@google.com>
 Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
 Mihai Borobocea <MihaiBorobocea@gmail.com>
 Mikael Tillenius <mikti42@gmail.com>
 Mike Andrews <mra@xoba.com>
+Mike Danese <mikedanese@google.com>
 Mike Rosset <mike.rosset@gmail.com>
 Mike Samuel <mikesamuel@gmail.com>
 Mike Solomon <msolo@gmail.com>
+Mikhail Gusarov <dottedmag@dottedmag.net>
 Mikhail Panchenko <m@mihasya.com>
 Miki Tebeka <miki.tebeka@gmail.com>
 Mikio Hara <mikioh.mikioh@gmail.com>
 Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
 Miquel Sabaté Solà <mikisabate@gmail.com>
 Mohit Agarwal <mohit@sdf.org>
+Monty Taylor <mordred@inaugust.com>
 Moriyoshi Koizumi <mozo@mozo.jp>
+Morten Siebuhr <sbhr@sbhr.dk>
 Môshe van der Sterre <moshevds@gmail.com>
 Mrunal Patel <mrunalp@gmail.com>
+Muhammed Uluyol <uluyol0@gmail.com>
 Nan Deng <monnand@gmail.com>
 Nathan John Youngman <nj@nathany.com>
 Nathan Otterness <otternes@cs.unc.edu>
@@ -633,17 +715,22 @@ Nathan Youngman <git@nathany.com>
 Nathan(yinian) Hu <nathanhu@google.com>
 Neelesh Chandola <neelesh.c98@gmail.com>
 Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
+Niall Sheridan <nsheridan@gmail.com>
 Nicholas Katsaros <nick@nickkatsaros.com>
 Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
 Nicholas Sullivan <nicholas.sullivan@gmail.com>
 Nicholas Waples <nwaples@gmail.com>
 Nick Cooper <nmvc@google.com>
 Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
+Nick Patavalis <nick.patavalis@gmail.com>
+Nick Petroni <npetroni@cs.umd.edu>
 Nicolas Kaiser <nikai@nikai.net>
 Nicolas Owens <mischief@offblast.org>
 Nicolas S. Dade <nic.dade@gmail.com>
+Niels Widger <niels.widger@gmail.com>
 Nigel Kerr <nigel.kerr@gmail.com>
 Nigel Tao <nigeltao@golang.org>
+Niko Dziemba <niko@dziemba.com>
 Nikolay Turpitko <nikolay@turpitko.com>
 Noah Campbell <noahcampbell@gmail.com>
 Nodir Turakulov <nodir@google.com>
@@ -653,7 +740,10 @@ Oling Cat <olingcat@gmail.com>
 Oliver Hookins <ohookins@gmail.com>
 Olivier Antoine <olivier.antoine@gmail.com>
 Olivier Duperray <duperray.olivier@gmail.com>
+Olivier Poitrey <rs@dailymotion.com>
 Olivier Saingre <osaingre@gmail.com>
+Omar Jarjur <ojarjur@google.com>
+Özgür Kesim <oec-go@kesim.org>
 Padraig Kitterick <padraigkitterick@gmail.com>
 Paolo Giarrusso <p.giarrusso@gmail.com>
 Paolo Martini <mrtnpaolo@gmail.com>
@@ -678,6 +768,7 @@ Paul Rosania <paul.rosania@gmail.com>
 Paul Sbarra <Sbarra.Paul@gmail.com>
 Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
 Paul van Brouwershaven <paul@vanbrouwershaven.com>
+Paul Wankadia <junyer@google.com>
 Pavel Paulau <pavel.paulau@gmail.com>
 Pavel Zinovkin <pavel.zinovkin@gmail.com>
 Pawel Knap <pawelknap88@gmail.com>
@@ -688,6 +779,7 @@ Petar Maymounkov <petarm@gmail.com>
 Peter Armitage <peter.armitage@gmail.com>
 Peter Collingbourne <pcc@google.com>
 Peter Froehlich <peter.hans.froehlich@gmail.com>
+Peter Gonda <pgonda@google.com>
 Peter Kleiweg <pkleiweg@xs4all.nl>
 Peter McKenzie <petermck@google.com>
 Peter Moody <pmoody@uber.com>
@@ -701,13 +793,17 @@ Peter Waller <peter.waller@gmail.com>
 Peter Weinberger <pjw@golang.org>
 Peter Williams <pwil3058@gmail.com>
 Phil Pennock <pdp@golang.org>
+Philip Hofer <phofer@umich.edu>
 Philip K. Warren <pkwarren@gmail.com>
+Pierre Durand <pierredurand@gmail.com>
 Pierre Roullon <pierre.roullon@gmail.com>
 Pieter Droogendijk <pieter@binky.org.uk>
 Pietro Gagliardi <pietro10@mac.com>
+Prashant Varanasi <prashant@prashantv.com>
 Preetam Jinka <pj@preet.am>
 Quan Yong Zhai <qyzhai@gmail.com>
 Quentin Perez <qperez@ocs.online.net>
+Quentin Smith <quentin@golang.org>
 Quoc-Viet Nguyen <afelion@gmail.com>
 Rahul Chaudhry <rahulchaudhry@chromium.org>
 Raif S. Naffah <go@naffah-raif.name>
@@ -717,12 +813,16 @@ Raph Levien <raph@google.com>
 Raul Silvera <rsilvera@google.com>
 Reinaldo de Souza Jr <juniorz@gmail.com>
 Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
+Rhys Hiltner <rhys@justin.tv>
+Ricardo Padilha <ricardospadilha@gmail.com>
 Richard Barnes <rlb@ipv.sx>
 Richard Crowley <r@rcrowley.org>
 Richard Eric Gavaletz <gavaletz@gmail.com>
+Richard Miller <miller.research@gmail.com>
 Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
 Rick Arnold <rickarnoldjr@gmail.com>
 Rick Hudson <rlh@golang.org>
+Riku Voipio <riku.voipio@linaro.org>
 Risto Jaakko Saarelma <rsaarelm@gmail.com>
 Rob Earhart <earhart@google.com>
 Rob Norman <rob.norman@infinitycloud.com>
@@ -742,6 +842,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
 Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
 Roger Pau Monné <royger@gmail.com>
 Roger Peppe <rogpeppe@gmail.com>
+Roland Shoemaker <rolandshoemaker@gmail.com>
 Ron Hashimoto <mail@h2so5.net>
 Ron Minnich <rminnich@gmail.com>
 Ross Light <light@google.com> <rlight2@gmail.com>
@@ -757,17 +858,23 @@ Ryan Seys <ryan@ryanseys.com>
 Ryan Slade <ryanslade@gmail.com>
 S.Çağlar Onur <caglar@10ur.org>
 Salmān Aljammāz <s@0x65.net>
+Sam Hug <samuel.b.hug@gmail.com>
 Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
+Sam Whited <sam@samwhited.com>
 Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
+Sami Commerot <samic@google.com>
 Sanjay Menakuru <balasanjay@gmail.com>
 Sasha Lionheart <lionhearts@google.com>
 Scott Barron <scott.barron@github.com>
+Scott Bell <scott@sctsm.com>
 Scott Ferguson <scottwferg@gmail.com>
 Scott Lawrence <bytbox@gmail.com>
+Scott Mansfield <smansfield@netflix.com>
 Scott Schwartz <scotts@golang.org>
 Scott Van Woudenberg <scottvw@google.com>
 Sean Burford <sburford@google.com>
 Sean Dolphin <Sean.Dolphin@kpcompass.com>
+Sean Harger <sharger@google.com>
 Sebastien Binet <seb.binet@gmail.com>
 Sébastien Paolacci <sebastien.paolacci@gmail.com>
 Sergei Skorobogatov <skorobo@rambler.ru>
@@ -775,20 +882,24 @@ Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
 Sergey Arseev <sergey.arseev@intel.com>
 Sergio Luis O. B. Correia <sergio@correia.cc>
 Seth Hoenig <seth.a.hoenig@gmail.com>
+Shahar Kohanim <skohanim@gmail.com>
 Shane Hansen <shanemhansen@gmail.com>
 Shaozhen Ding <dsz0111@gmail.com>
 Shawn Ledbetter <sledbetter@google.com>
 Shawn Smith <shawn.p.smith@gmail.com>
 Shawn Walker-Salas <shawn.walker@oracle.com>
 Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
+Shinji Tanaka <shinji.tanaka@gmail.com>
 Shivakumar GN <shivakumar.gn@gmail.com>
 Shun Fan <sfan@google.com>
 Silvan Jegen <s.jegen@gmail.com>
+Simon Jefford <simon.jefford@gmail.com>
 Simon Whitehead <chemnova@gmail.com>
 Sokolov Yura <funny.falcon@gmail.com>
 Spencer Nelson <s@spenczar.com>
 Spring Mc <heresy.mc@gmail.com>
 Srdjan Petrovic <spetrovic@google.com>
+Sridhar Venkatakrishnan <sridhar@laddoo.net>
 StalkR <stalkr@stalkr.net>
 Stan Schwertly <stan@schwertly.com>
 Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
@@ -803,12 +914,14 @@ Steve Streeting <steve@stevestreeting.com>
 Steven Elliot Harris <seharris@gmail.com>
 Steven Hartland <steven.hartland@multiplay.co.uk>
 Sugu Sougoumarane <ssougou@gmail.com>
+Suharsh Sivakumar <suharshs@google.com>
 Sven Almgren <sven@tras.se>
 Szabolcs Nagy <nsz@port70.net>
 Tad Glines <tad.glines@gmail.com>
 Taj Khattra <taj.khattra@gmail.com>
 Takashi Matsuo <tmatsuo@google.com>
 Takeshi YAMANASHI <9.nashi@gmail.com>
+Tal Shprecher <tshprecher@gmail.com>
 Tamir Duberstein <tamird@gmail.com>
 Tarmigan Casebolt <tarmigan@gmail.com>
 Taru Karttunen <taruti@taruti.net>
@@ -820,13 +933,20 @@ Thomas Desrosiers <thomasdesr@gmail.com>
 Thomas Habets <habets@google.com>
 Thomas Kappler <tkappler@gmail.com>
 Thorben Krueger <thorben.krueger@gmail.com>
+Tilman Dilo <tilman.dilo@gmail.com>
 Tim Cooijmans <timcooijmans@gmail.com>
+Tim Ebringer <tim.ebringer@gmail.com>
 Tim Hockin <thockin@google.com>
+Tim Swast <swast@google.com>
 Timo Savola <timo.savola@gmail.com>
 Timo Truyts <alkaloid.btx@gmail.com>
+Timothy Studd <tim@timstudd.com>
+Tipp Moseley <tipp@google.com>
 Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
+Toby Burress <kurin@google.com>
 Todd Neal <todd@tneal.org>
 Todd Wang <toddwang@gmail.com>
+Tom Bergan <tombergan@google.com>
 Tom Heng <zhm20070928@gmail.com>
 Tom Linford <tomlinford@gmail.com>
 Tom Szymanski <tgs@google.com>
@@ -840,11 +960,13 @@ Trey Tacon <ttacon@gmail.com>
 Tudor Golubenco <tudor.g@gmail.com>
 Tyler Bunnell <tylerbunnell@gmail.com>
 Tyler Treat <ttreat31@gmail.com>
+Tzu-Jung Lee <roylee17@currant.com>
 Ugorji Nwoke <ugorji@gmail.com>
 Ulf Holm Nielsen <doktor@dyregod.dk>
 Ulrich Kunitz <uli.kunitz@gmail.com>
 Uriel Mangado <uriel@berlinblue.org>
 Uttam C Pawar <uttam.c.pawar@intel.com>
+Vadim Grek <vadimprog@gmail.com>
 Vadim Vygonets <unixdj@gmail.com>
 Vega Garcia Luis Alfonso <vegacom@gmail.com>
 Vincent Ambo <tazjin@googlemail.com>
@@ -852,9 +974,11 @@ Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
 Vincent Vanackere <vincent.vanackere@gmail.com>
 Vinu Rajashekhar <vinutheraj@gmail.com>
 Vish Subramanian <vish@google.com>
+Vishvananda Ishaya <vishvananda@gmail.com>
 Vlad Krasnov <vlad@cloudflare.com>
 Vladimir Nikishenko <vova616@gmail.com>
 Volker Dobler <dr.volker.dobler@gmail.com>
+Wedson Almeida Filho <wedsonaf@google.com>
 Wei Guangjing <vcc.163@gmail.com>
 Will Chan <willchan@google.com>
 Will Norris <willnorris@google.com>
@@ -864,6 +988,7 @@ William Josephson <wjosephson@gmail.com>
 William Orr <will@worrbase.com> <ay1244@gmail.com>
 Xia Bin <snyh@snyh.org>
 Xing Xing <mikespook@gmail.com>
+Xudong Zhang <felixmelon@gmail.com>
 Yan Zou <yzou@google.com>
 Yann Kerhervé <yann.kerherve@gmail.com>
 Yao Zhang <lunaria21@gmail.com>
@@ -879,6 +1004,7 @@ Yusuke Kagiwada <block.rxckin.beats@gmail.com>
 Yuusei Kuwana <kuwana@kumama.org>
 Yuval Pavel Zholkover <paulzhol@gmail.com>
 Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
+Zhongwei Yao <zhongwei.yao@arm.com>
 Ziad Hatahet <hatahet@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
 申习之 <bronze1man@gmail.com>
index 09e6cf1f965cb272b6c32b9927a1748487238167..5ae56c126ada2033127dd3c65acbd2c0639c9842 100644 (file)
@@ -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
@@ -158,22 +167,54 @@ 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)
-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 +228,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 +240,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
index 5d20d3887ae96cbb841cfb1e50fd0dce77d5ff3c..992f176014e234fb614d9372948a62a52e6c43a9 100644 (file)
@@ -89,7 +89,7 @@ gofmt</a> command with more general options.</td>
 </tr>
 
 <tr>
-<td><a href="//godoc.org/golang.org/x/tools/cmd/vet/">vet</a></td>
+<td><a href="/cmd/vet/">vet</a></td>
 <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
 <td>Vet examines Go source code and reports suspicious constructs, such as Printf
 calls whose arguments do not align with the format string.</td>
index 1cd6f37d34e95082e802b2ca75951b7fe926dd18..bcf7b25c51158057b0c868050327cbf3ac8a30b0 100644 (file)
@@ -353,10 +353,13 @@ with a thorough description of your 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.
 </p>
 
 <p>
@@ -364,7 +367,7 @@ After editing, the template might now read:
 </p>
 
 <pre>
-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
index 4ea3fae31836e4bd2e764fd525aba4165232aaae..1e66c0c6145faee0cf5a0dfd86c0e21b9a556b03 100644 (file)
@@ -2014,7 +2014,7 @@ then make the receiver for the method a value of that type.
 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.
 }
 </pre>
 <p>
diff --git a/doc/go1.7.html b/doc/go1.7.html
new file mode 100644 (file)
index 0000000..46c5754
--- /dev/null
@@ -0,0 +1,1132 @@
+<!--{
+       "Title": "Go 1.7 Release Notes DRAFT",
+       "Path":  "/doc/go1.7",
+       "Template": true
+}-->
+
+<!--
+for acme:
+Edit .,s;^PKG:([a-z][A-Za-z0-9_/]+);<a href="/pkg/\1/"><code>\1</code></a>;g
+Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\3</code></a>\4;g
+Edit .,s;^FULL:([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\1.\2\3</code></a>\4;g
+Edit .,s;^DPKG:([a-z][A-Za-z0-9_/]+);<dl id="\1"><a href="/pkg/\1/">\1</a></dl>;g
+
+rsc last updated through 6729576
+-->
+
+<!--
+NOTE: In this document and others in this directory, the convention is to
+set fixed-width phrases with non-fixed-width spaces, as in
+<code>hello</code> <code>world</code>.
+Do not send CLs removing the interior tags from such phrases.
+-->
+
+<style>
+ul li { margin: 0.5em 0; }
+</style>
+
+<p>
+<!-- TODO: REMOVE THIS COMMENT -->
+<!-- TODO: Also remove "DRAFT" in the "Title" at the top of this file. -->
+<i>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.
+</i>
+</p>
+<h2 id="introduction">Introduction to Go 1.7</h2>
+
+<p>
+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 <a href="/doc/go1compat.html">promise of compatibility</a>.
+We expect almost all Go programs to continue to compile and run as before.
+</p>
+
+<p>
+The release <a href="#ports">adds a port to IBM LinuxOne</a>;
+<a href="#compiler">updates the x86-64 compiler back end</a> to generate more efficient code;
+includes the <a href="#context">context package</a>, promoted from the
+<a href="https://golang.org/x/net/context">x/net subrepository</a>
+and now used in the standard library;
+and <a href="#testing">adds support in the testing package</a> for
+creating hierarchies of tests and benchmarks.
+The release also <a href="#cmd/go">finalizes the vendoring support</a>
+started in Go 1.5, making it a standard feature.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+There is one tiny language change in this release.
+The section on <a href="/ref/spec#Terminating_statements">terminating statements</a>
+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 <a href="/pkg/go/types/"><code>go/types</code></a>
+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.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+Go 1.7 adds an experimental port to <a href="https://en.wikipedia.org/wiki/Linux_on_z_Systems">Linux on z Systems</a> (<code>linux/s390x</code>)
+and the beginning of a port to Plan 9 on ARM (<code>plan9/arm</code>).
+</p>
+
+<p>
+The experimental ports to Linux on 64-bit MIPS (<code>linux/mips64</code> and <code>linux/mips64le</code>)
+added in Go 1.6 now have full support for cgo and external linking.
+</p>
+
+<p>
+The experimental port to Linux on big-endian 64-bit PowerPC (<code>linux/ppc64</code>)
+now requires the POWER8 architecture or later.
+</p>
+
+<p>
+The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="http://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="cmd/asm">Assembler</h3>
+
+<p>
+For 64-bit ARM systems, the vector register names have been
+corrected to <code>V0</code> through <code>V31</code>;
+previous releases incorrectly referred to them as <code>V32</code> through <code>V63</code>.
+</p>
+
+<p>
+For 64-bit x86 systems, the following instructions have been added:
+<code>PCMPESTRI</code>,
+<code>RORXL</code>,
+<code>RORXQ</code>,
+<code>VINSERTI128</code>,
+<code>VPADDD</code>,
+<code>VPADDQ</code>,
+<code>VPALIGNR</code>,
+<code>VPBLENDD</code>,
+<code>VPERM2F128</code>,
+<code>VPERM2I128</code>,
+<code>VPOR</code>,
+<code>VPSHUFB</code>,
+<code>VPSHUFD</code>,
+<code>VPSLLD</code>,
+<code>VPSLLDQ</code>,
+<code>VPSLLQ</code>,
+<code>VPSRLD</code>,
+<code>VPSRLDQ</code>,
+and
+<code>VPSRLQ</code>.
+</p>
+
+<h3 id="compiler">Compiler Toolchain</h3>
+
+<p>
+This release includes a new code generation back end for 64-bit x86 systems,
+following a <a href="https://golang.org/s/go17ssa">proposal from 2015</a>
+that has been under development since then.
+The new back end, based on
+<a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">SSA</a>,
+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
+<a href="https://golang.org/test/bench/go1/">our benchmark programs</a> by 5-35%.
+</p>
+
+<p>
+For this release, the new back end can be disabled by passing
+<code>-ssa=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new back end disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+For this release, the new export format can be disabled by passing
+<code>-newexport=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new export format disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+The linker's <code>-X</code> option no longer supports the unusual two-argument form
+<code>-X</code> <code>name</code> <code>value</code>,
+as <a href="/doc/go1.6#compiler">announced</a> in the Go 1.6 release
+and in warnings printed by the linker.
+Use <code>-X</code> <code>name=value</code> instead.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+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%.
+</p>
+
+<h3 id="cmd/cgo">Cgo</h3>
+
+<p>
+Packages using <a href="/cmd/cgo/">cgo</a> 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.
+</p>
+
+<p>
+Go bindings may now use a new helper function <code>C.CBytes</code>.
+In contrast to <code>C.CString</code>, which takes a Go <code>string</code>
+and returns a <code>*C.byte</code> (a C <code>char*</code>),
+<code>C.CBytes</code> takes a Go <code>[]byte</code>
+and returns an <code>unsafe.Pointer</code> (a C <code>void*</code>).
+</p>
+
+<p>
+Packages and binaries built using <code>cgo</code> 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 <code>-fdebug-prefix-map</code> option),
+those builds should finally be deterministic.
+</p>
+
+<h3 id="gccgo">Gccgo</h3>
+
+<p>
+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.
+</p>
+
+<h3 id="cmd/go">Go command</h3>
+
+<p>
+The <a href="/cmd/go/"><code>go</code></a> command's basic operation
+is unchanged, but there are a number of changes worth noting.
+</p>
+
+<p>
+This release removes support for the <code>GO15VENDOREXPERIMENT</code> environment variable,
+as <a href="/doc/go1.6#go_command">announced</a> in the Go 1.6 release.
+<a href="https://golang.org/s/go15vendor">Vendoring support</a>
+is now a standard feature of the <code>go</code> command and toolchain.
+</p>
+
+<p>
+The <code>Package</code> data structure made available to
+“<code>go</code> <code>list</code>” now includes a
+<code>StaleReason</code> field explaining why a particular package
+is or is not considered stale (in need of rebuilding).
+This field is available to the <code>-f</code> or <code>-json</code>
+options and is useful for understanding why a target is being rebuilt.
+</p>
+
+<p>
+The “<code>go</code> <code>get</code>” command now supports
+import paths referring to <code>git.openstack.org</code>.
+</p>
+
+<p>
+This release adds experimental, minimal support for building programs using
+<a href="/pkg/go/build#hdr-Binary_Only_Packages">binary-only packages</a>,
+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 “<code>go</code> <code>get</code>” command.
+</p>
+
+<h3 id="cmd/doc">Go doc</h3>
+
+<p>
+The “<code>go</code> <code>doc</code>” command
+now groups constructors with the type they construct,
+following <a href="/cmd/godoc/"><code>godoc</code></a>.
+</p>
+
+<h3 id="cmd/vet">Go vet</h3>
+
+<p>
+The “<code>go</code> <code>vet</code>” command
+has more accurate analysis in its <code>-copylock</code> and <code>-printf</code> checks,
+and a new <code>-tests</code> check that checks the name and signature of likely test functions.
+To avoid confusion with the new <code>-tests</code> check, the old, unadvertised
+<code>-test</code> option has been removed; it was equivalent to <code>-all</code> <code>-shadow</code>.
+</p>
+
+<h3 id="cmd/dist">Go tool dist</h3>
+
+<p>
+The new subcommand “<code>go</code> <code>tool</code> <code>dist</code> <code>list</code>”
+prints all supported operating system/architecture pairs.
+</p>
+
+<h3 id="cmd/trace">Go tool trace</h3>
+
+<p>
+The “<code>go</code> <code>tool</code> <code>trace</code>” command,
+<a href="/doc/go1.5#trace_command">introduced in Go 1.5</a>,
+has been refined in various ways.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+Although the trace file format has changed in this release,
+the Go 1.7 tools can still read traces from earlier releases.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+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%.
+</p>
+
+<p>
+<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
+There have been significant optimizations bringing more than 10% improvements
+to implementations in the
+<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
+<a href="/pkg/crypto/sha256/"><code>crypto/sha256</code></a>,
+<a href="/pkg/encoding/binary/"><code>encoding/binary</code></a>,
+<a href="/pkg/fmt/"><code>fmt</code></a>,
+<a href="/pkg/hash/adler32/"><code>hash/adler32</code></a>,
+<a href="/pkg/hash/crc32/"><code>hash/crc32</code></a>,
+<a href="/pkg/hash/crc64/"><code>hash/crc64</code></a>,
+<a href="/pkg/image/color/"><code>image/color</code></a>,
+<a href="/pkg/math/big/"><code>math/big</code></a>,
+<a href="/pkg/strconv/"><code>strconv</code></a>,
+<a href="/pkg/strings/"><code>strings</code></a>,
+<a href="/pkg/unicode/"><code>unicode</code></a>,
+and
+<a href="/pkg/unicode/utf16/"><code>unicode/utf16</code></a>
+packages.
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3 id="context">Context</h3>
+
+<p>
+Go 1.7 moves the <code>golang.org/x/net/context</code> package
+into the standard library as <a href="/pkg/context/"><code>context</code></a>.
+This allows the use of contexts for cancellation, timeouts, and passing
+request-scoped data in other standard library packages,
+including
+<a href="#net">net</a>,
+<a href="#net/http">net/http</a>,
+and
+<a href="#os/exec">os/exec</a>,
+as noted below.
+</p>
+
+<p>
+For more information about contexts, see the
+<a href="/pkg/context/">package documentation</a>
+and the Go blog post
+“<a href="https://blog.golang.org/context">Go Concurrent Patterns: Context</a>.”
+</p>
+
+<h3 id="testing">Testing</h3>
+
+<p>
+The <code>testing</code> package now supports the definition
+of tests with subtests and benchmarks with sub-benchmarks.
+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 <a href="/pkg/testing/#hdr-Subtests_and_Sub_benchmarks">package documentation</a> for details.
+</p>
+
+<h3 id="runtime">Runtime</h3>
+
+<p>
+All panics started by the runtime now use panic values
+that implement both the builtin <a href="/ref/spec#Errors">error</code>,
+and
+<a href="/pkg/runtime/#Error"><code>runtime.Error</code></a>,
+as
+<a href="/ref/spec#Run_time_panics">required by the language specification</a>.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#KeepAlive"><code>KeepAlive</code></a>
+provides an explicit mechanism for declaring
+that an allocated object must be considered reachable
+at a particular point in a program,
+typically to delay the execution of an associated finalizer.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#CallersFrames"><code>CallersFrames</code></a>
+translates a PC slice obtained from
+<a href="/pkg/runtime/#Callers"><code>Callers</code></a>
+into a sequence of frames corresponding to the call stack.
+This new API should be preferred instead of direct use of
+<a href="/pkg/runtime/#FuncForPC"><code>FuncForPC</code></a>,
+because the frame sequence can more accurately describe
+call stacks with inlined function calls.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#SetCgoTraceback"><code>SetCgoTraceback</code></a>
+facilitates tighter integration between Go and C code executing
+in the same process called using cgo.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+On Windows, Go programs in Go 1.5 and earlier forced
+the global Windows timer resolution to 1ms at startup
+by calling <code>timeBeginPeriod(1)</code>.
+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.
+</p>
+
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+As always, there are various minor changes and updates to the library,
+made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
+in mind.
+</p>
+
+<dl id="bufio"><a href="/pkg/bufio/">bufio</a></dl>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/bufio/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bufio/#Reader.Peek"><code>Peek</code></a> method
+were asked for more bytes than fit in the underlying buffer,
+it would return an empty slice and the error <code>ErrBufferFull</code>.
+Now it returns the entire underlying buffer, still accompanied by the error <code>ErrBufferFull</code>.
+</p>
+</dd>
+
+<dl id="bytes"><a href="/pkg/bytes/">bytes</a></dl>
+
+<dd>
+<p>
+The new functions
+<a href="/pkg/bytes/#ContainsAny"><code>ContainsAny</code></a> and
+<a href="/pkg/bytes/#ContainsRune"><code>ContainsRune</code></a>
+have been added for symmetry with
+the <a href="/pkg/strings/"><code>strings</code></a> package.
+</p>
+
+<p>
+In previous releases of Go, if
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bytes/#Reader.Read"><code>Read</code></a> 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
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
+</p>
+
+<p>
+The
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/bytes/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+
+<dl id="compress/flate"><a href="/pkg/compress/flate/">compress/flate</a></dl>
+
+<dd>
+<p>
+As noted above,
+there are significant performance optimizations throughout the package.
+Decompression speed is improved by about 10%,
+while compression speed for <code>DefaultCompression</code> is roughly doubled.
+</p>
+
+<p>
+In addition to those general improvements,
+the
+<code>BestSpeed</code>
+compressor has been replaced entirely and uses an
+algorithm similar to <a href="https://github.com/google/snappy">Snappy</a>,
+resulting in about a 2.5X speed increase,
+although the output can be 5-10% larger than with the previous algorithm.
+</p>
+
+<p>
+There is also a new compression level
+<code>HuffmanOnly</code>
+that applies Huffman but not Lempel-Ziv encoding.
+<a href="https://blog.klauspost.com/constant-time-gzipzip-compression/">Forgoing Lempel-Ziv encoding</a> means that
+<code>HuffmanOnly</code> runs about 3X faster than the new <code>BestSpeed</code>
+but at the cost of producing compressed outputs that are 20-40% larger than those
+generated by the new <code>BestSpeed</code>.
+</p>
+</dd>
+
+<dl id="crypto/tls"><a href="/pkg/crypto/tls/">crypto/tls</a></dl>
+
+<dd>
+<p>
+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.
+Setting
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>DynamicRecordSizingDisabled</code> 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.
+</p>
+
+<p>
+The TLS client now has optional, limited support for server-initiated renegotiation,
+enabled by setting the
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>Renegotiation</code> field.
+This is needed for connecting to many Microsoft Azure servers.
+</p>
+
+<p>
+The errors returned by the package now consistently begin with a
+<code>tls:</code> prefix.
+In past releases, some errors used a <code>crypto/tls:</code> prefix,
+some used a <code>tls:</code> prefix, and some had no prefix at all.
+</p>
+
+<p>
+When generating self-signed certificates, the package no longer sets the
+“Authority Key Identifier” field by default.
+</p>
+</dd>
+
+<dl id="crypto/x509"><a href="/pkg/crypto/x509/">crypto/x509</a></dl>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
+provides access to the entire system certificate pool if available.
+There is also a new associated error type
+<a href="/pkg/crypto/x509/#SystemRootsError"><code>SystemRootsError</code></a>.
+</p>
+</dd>
+
+<dl id="debug/dwarf"><a href="/pkg/debug/dwarf/">debug/dwarf</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/debug/dwarf/#Reader"><code>Reader</code></a> type's new
+<a href="/pkg/debug/dwarf/#Reader.SeekPC"><code>SeekPC</code></a> method and the
+<a href="/pkg/debug/dwarf/#Data"><code>Data</code></a> type's new
+<a href="/pkg/debug/dwarf/#Ranges"><code>Ranges</code></a> method
+help to find the compilation unit to pass to a
+<a href="/pkg/debug/dwarf/#LineReader"><code>LineReader</code></a>
+and to identify the specific function for a given program counter.
+</p>
+</dd>
+
+<dl id="debug/elf"><a href="/pkg/debug/elf/">debug/elf</a></dl>
+
+<dd>
+<p>
+The new
+<a href="/pkg/debug/elf/#R_390"><code>R_390</code></a> relocation type
+and its many predefined constants
+support the S390 port.
+</p>
+</dd>
+
+<dl id="encoding/asn1"><a href="/pkg/encoding/asn1/">encoding/asn1</a></dl>
+
+<dd>
+<p>
+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.
+</p>
+</dd>
+
+<dl id="encoding/json"><a href="/pkg/encoding/json/">encoding/json</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetIndent"><code>SetIndent</code></a> method
+sets the indentation parameters for JSON encoding,
+like in the top-level
+<a href="/pkg/encoding/json/#Indent"><code>Indent</code></a> function.
+</p>
+
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetEscapeHTML"><code>SetEscapeHTML</code></a> method
+controls whether the
+<code>&#x26;</code>, <code>&#x3c;</code>, and <code>&#x3e;</code>
+characters in quoted strings should be escaped as
+<code>\u0026</code>, <code>\u003c</code>, and <code>\u003e</code>,
+respectively.
+As in previous releases, the encoder defaults to applying this escaping,
+to avoid certain problems that can arise when embedding JSON in HTML.
+</p>
+
+<p>
+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
+<code>MarshalJSON</code>
+(see
+<a href="/pkg/encoding/json/#Marshaler"><code>Marshaler</code></a>)
+or
+<code>MarshalText</code>
+(see
+<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a>)
+methods,
+as well as support for decoding maps using non-string keys that implement
+<code>UnmarshalJSON</code>
+(see
+<a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>)
+or
+<code>UnmarshalText</code>
+(see
+<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>)
+methods.
+These methods are ignored for keys with string types in order to preserve
+the encoding and decoding used in earlier versions of Go.
+</p>
+
+<p>
+When encoding a slice of typed bytes,
+<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>
+now generates an array of elements encoded using
+that byte type's
+<code>MarshalJSON</code>
+or
+<code>MarshalText</code>
+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
+<code>UnmarshalJSON</code>
+or
+<code>UnmarshalText</code>
+as appropriate),
+so this change should be semantically backwards compatible with earlier versions of Go,
+even though it does change the chosen encoding.
+</p>
+</dd>
+
+<dl id="go/build"><a href="/pkg/go/build/">go/build</a></dl>
+
+<dd>
+<p>
+To implement the go command's new support for binary-only packages
+and for Fortran code in cgo-based packages,
+the
+<a href="/pkg/go/build/#Package"><code>Package</code></a> type
+adds new fields <code>BinaryOnly</code>, <code>CgoFFLAGS</code>, and <code>FFiles</code>.
+</p>
+</dd>
+
+<dl id="go/doc"><a href="/pkg/go/doc/">go/doc</a></dl>
+
+<dd>
+<p>
+To support the corresponding change in <code>go</code> <code>test</code> described above,
+<a href="/pkg/go/doc/#Example"><code>Example</code></a> struct adds a Unordered field
+indicating whether the example may generate its output lines in any order.
+</p>
+</dd>
+
+<dl id="io"><a href="/pkg/io/">io</a></dl>
+
+<dd>
+<p>
+The package adds new constants
+<code>SeekStart</code>, <code>SeekCurrent</code>, and <code>SeekEnd</code>,
+for use with
+<a href="/pkg/io/#Seeker"><code>Seeker</code></a>
+implementations.
+These constants are preferred over <code>os.SEEK_SET</code>, <code>os.SEEK_CUR</code>, and <code>os.SEEK_END</code>,
+but the latter will be preserved for compatibility.
+</p>
+</dd>
+
+<dl id="math/big"><a href="/pkg/math/big/">math/big</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/math/big/#Float"><code>Float</code></a> type adds
+<a href="/pkg/math/big/#Float.GobEncode"><code>GobEncode</code></a> and
+<a href="/pkg/math/big/#Float.GobDecode"><code>GobDecode</code></a> methods,
+so that values of type <code>Float</code> can now be encoded and decoded using the
+<a href="/pkg/encoding/gob/"><code>encoding/gob</code></a>
+package.
+</p>
+</dd>
+
+<dl id="mime/multipart"><a href="/pkg/mime/multipart/">mime/multipart</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/mime/multipart/#Writer"><code>Writer</code></a>
+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.
+</p>
+</dd>
+
+<dl id="net"><a href="/pkg/net/">net</a></dl>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/#Dialer"><code>Dialer</code></a> type has a new method
+<a href="/pkg/net/#Dialer.DialContext"><code>DialContext</code></a>, like
+<a href="/pkg/net/#Dialer.Dial"><code>Dial</code></a> but adding the
+<a href="/pkg/context/#Context"><code>context.Context</code></a>
+for the dial operation.
+The context is intended to obsolete the <code>Dialer</code>'s
+<code>Cancel</code> and <code>Deadline</code> fields,
+but the implementation continues to respect them,
+for backwards compatibility.
+</p>
+
+<p>
+The
+<a href="/pkg/net/#IP"><code>IP</code></a> type's
+<a href="/pkg/net/#IP.String"><code>String</code></a> method has changed its result for invalid <code>IP</code> addresses.
+In past releases, if an <code>IP</code> byte slice had length other than 0, 4, or 16, <code>String</code>
+returned <code>"?"</code>.
+Go 1.7 adds the hexadecimal encoding of the bytes, as in <code>"?12ab"</code>.
+</p>
+
+<p>
+The pure Go <a href="/pkg/net/#hdr-Name_Resolution">name resolution</a>
+implementation now respects <code>nsswtch.conf</code>'s
+stated preference for the priority of DNS lookups compared to
+local file (that is, <code>/etc/hosts</code>) lookups.
+</p>
+</dd>
+
+<dl id="net/http"><a href="/pkg/net/http/">net/http</a></dl>
+
+<dd>
+<p>
+<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>'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.
+</p>
+
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/http/#Request"><code>Request</code></a> has a new methods
+<a href="/pkg/net/http/#Request.Context"><code>Context</code></a>, to retrieve the associated context, and
+<a href="/pkg/net/http/#Request.WithContext"><code>WithContext</code></a>, to construct a copy of <code>Request</code>
+with a modified context.
+</p>
+
+<p>
+In the
+<a href="/pkg/net/http/#Server"><code>Server</code></a> implementation,
+<a href="/pkg/net/http/#Server.Serve"><code>Serve</code></a> records in the request context
+both the underlying <code>*Server</code> using the key <code>ServerContextKey</code>
+and the local address on which the request was received (a
+<a href="/pkg/net/#Addr"><code>Addr</code></a>) using the key <code>LocalAddrContextKey</code>.
+For example, the address on which a request received is
+<code>req.Context().Value(http.LocalAddrContextKey).(net.Addr)</code>.
+</p>
+
+<p>
+The server implementation now
+pads response codes less than 100 to three digits
+as required by the protocol,
+so that <code>w.WriteHeader(5)</code> uses the HTTP response
+status <code>005</code>, not just <code>5</code>.
+</p>
+
+<p>
+In the client, the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> implementation passes the request context
+to any dial operation connecting to the remote server.
+If a custom dialer is needed, the new <code>Transport</code> field
+<code>DialContext</code> is preferred over the existing <code>Dial</code> field,
+to allow the transport to supply a context.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> also adds fields
+<code>IdleConnTimeout</code>,
+<code>MaxIdleConns</code>,
+and
+<code>MaxResponseHeaderBytes</code>
+to help control client resources consumed
+by idle or chatty servers.
+</p>
+
+<p>
+A
+<a href="/pkg/net/http/#Client"><code>Client</code></a>'s configured <code>CheckRedirect</code> function can now
+return <code>ErrUseLastResponse</code> 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 <code>CheckRedirect</code> function
+as <code>req.Response</code>.
+</p>
+
+<p>
+Since Go 1, the default behavior of the HTTP client is
+to request server-side compression
+using the <code>Accept-Encoding</code> request header
+and then to uncompress the response body transparently,
+and this behavior is adjustable using the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>'s <code>DisableCompression</code> field.
+In Go 1.7, to aid the implementation of HTTP proxies, the
+<a href="/pkg/net/http/#Response"><code>Response</code></a>'s new
+<code>Uncompressed</code> field reports whether
+this transparent uncompression took place.
+</p>
+
+<p>
+<a href="/pkg/net/http/#DetectContentType"><code>DetectContentType</code></a>
+adds support for a few new audio and video content types.
+</p>
+</dd>
+
+<dl id="net/http/cgi"><a href="/pkg/net/http/cgi/">net/http/cgi</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/cgi/#Handler"><code>Handler</code></a>
+adds a new field
+<code>Stderr</code>
+that allows redirection of the child process's
+standard error away from the host process's
+standard error.
+</p>
+</dd>
+
+<dl id="net/http/httptest"><a href="/pkg/net/http/httptest/">net/http/httptest</a></dl>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/net/http/httptest/#NewRequest"><code>NewRequest</code></a>
+prepares a new
+<a href="/pkg/net/http/#Request"><code>http.Request</code></a>
+suitable for passing to an
+<a href="/pkg/net/http/#Handler"><code>http.Handler</code></a> during a test.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/httptest/#ResponseRecorder"><code>ResponseRecorder</code></a>'s new
+<a href="/pkg/net/http/httptest/#ResponseRecorder.Result"><code>Result</code></a> method
+returns the recorded
+<a href="/pkg/net/http/#Response"><code>http.Response</code></a>.
+Tests that need to check the response's headers or trailers
+should call <code>Result</code> and inspect the response fields
+instead of accessing
+<code>ResponseRecorder</code>'s <code>HeaderMap</code> directly.
+</p>
+</dd>
+
+<dl id="net/http/httputil"><a href="/pkg/net/http/httputil/">net/http/httputil</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> implementation now responds with “502 Bad Gateway”
+when it cannot reach a back end; in earlier releases it responded with “500 Internal Server Error.”
+</p>
+
+<p>
+Both
+<a href="/pkg/net/http/httputil/#ClientConn"><code>ClientConn</code></a> and
+<a href="/pkg/net/http/httputil/#ServerConn"><code>ServerConn</code></a> 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
+<a href="/pkg/net/http/#Client"><code>http.Client</code></a>,
+<a href="/pkg/net/http/#Transport"><code>http.Transport</code></a>,
+and
+<a href="/pkg/net/http/#Server"><code>http.Server</code></a>
+instead.
+</p>
+</dd>
+
+<dl id="net/http/pprof"><a href="/pkg/net/http/pprof/">net/http/pprof</a></dl>
+
+<dd>
+<p>
+The runtime trace HTTP handler, installed to handle the path <code>/debug/pprof/trace</code>,
+now accepts a fractional number in its <code>seconds</code> query parameter,
+allowing collection of traces for intervals smaller than one second.
+This is especially useful on busy servers.
+</p>
+</dd>
+
+<dl><a href="/pkg/net/mail/">net/mail</a></dl>
+
+<dd>
+<p>
+The address parser now allows unescaped UTF-8 text in addresses
+following <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>,
+but it does not apply any normalization to the result.
+For compatibility with older mail parsers,
+the address encoder, namely
+<a href="/pkg/net/mail/#Address"><code>Address</code></a>'s
+<a href="/pkg/net/mail/#Address.String"><code>String</code></a> method,
+continues to escape all UTF-8 text following <a href="https://tools.ietf.org/html/rfc5322">RFC 5322</a>,
+</p>
+</dd>
+
+<dl id="net/url"><a href="/pkg/net/url/">net/url</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/url/#URL"><code>URL</code></a>'s
+new <code>ForceQuery</code> field
+records whether the URL must have a query string,
+in order to distinguish URLs without query strings (like <code>/search</code>)
+from URLs with empty query strings (like <code>/search?</code>).
+</p>
+</dd>
+
+<dl id="os"><a href="/pkg/os/">os</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/os/#File"><code>File</code></a>
+type adds a new
+<a href="/pkg/os/#File.Size"><code>Size</code></a>
+method, so that <code>File</code> implements the new
+<a href="/pkg/io/#SizedReaderAt"><code>SizedReaderAt</code></a> method.
+</p>
+
+<p>
+<a href="/pkg/os/#IsExists"><code>IsExists</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
+on systems where that error exists.
+</p>
+
+<p>
+On Windows,
+<a href="/pkg/os/#Remove"><code>Remove</code></a> now removes read-only files when possible,
+making the implementation behave as on
+non-Windows systems.
+</p>
+</dd>
+
+<dl id="os/exec"><a href="/pkg/os/exec/">os/exec</a></dl>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>,
+the new constructor
+<a href="/pkg/os/exec/#CommandContext"><code>CommandContext</code></a>
+is like
+<a href="/pkg/os/exec/#Command"><code>Command</code></a> but includes a context that can be used to cancel the command execution.
+</p>
+</dd>
+
+<dl id="os/user"><a href="/pkg/os/user/">os/user</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/os/user/#Current"><code>Current</code></a>
+function is now implemented even when cgo is not available.
+</p>
+
+<p>
+The new
+<a href="/pkg/os/user/#Group"><code>Group</code></a> type,
+along with the lookup functions
+<a href="/pkg/os/user/#LookupGroup"><code>LookupGroup</code></a> and
+<a href="/pkg/os/user/#LookupGroupId"><code>LookupGroupId</code></a>
+and the new field <code>GroupIds</code> in the <code>User</code> struct,
+provides access to system-specific user group information.
+</p>
+</dd>
+
+<dl id="reflect"><a href="/pkg/reflect/">reflect</a></dl>
+
+<dd>
+<p>
+Although
+<a href="/pkg/reflect/#Value"><code>Value</code></a>'s
+<a href="/pkg/reflect/#Value.Field"><code>Field</code></a> method has always been documented to panic
+if the given field number <code>i</code> is out of range, it has instead
+silently returned a zero
+<a href="/pkg/reflect/#Value"><code>Value</code></a>.
+Go 1.7 changes the method to behave as documented.
+</p>
+
+<p>
+The new
+<a href="/pkg/reflect/#StructOf"><code>StructOf</code></a>
+function constructs a struct type at run time.
+It completes the set of type constructors, joining
+<a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a>,
+<a href="/pkg/reflect/#ChanOf"><code>ChanOf</code></a>,
+<a href="/pkg/reflect/#FuncOf"><code>FuncOf</code></a>,
+<a href="/pkg/reflect/#MapOf"><code>MapOf</code></a>,
+<a href="/pkg/reflect/#PtrTo"><code>PtrTo</code></a>,
+and
+<a href="/pkg/reflect/#SliceOf"><code>SliceOf</code></a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/#StructTag"><code>StructTag</code></a>'s
+new method
+<a href="/pkg/reflect/#StructTag.Lookup"><code>Lookup</code></a>
+is like
+<a href="/pkg/reflect/#StructTag.Get"><code>Get</code></a>
+but distinguishes the tag not containing the given key
+from the tag associating an empty string with the given key.
+</p>
+
+<p>
+The
+<a href="/pkg/reflect/#Type.Method"><code>Method</code></a> and
+<a href="/pkg/reflect/#Type.NumMethod"><code>NumMethod</code></a>
+methods of
+<a href="/pkg/reflect/#Type"><code>Type</code></a> and
+<a href="/pkg/reflect/#Value"><code>Value</code></a>
+no longer return or count unexported methods.
+</p>
+</dd>
+
+<dl id="strings"><a href="/pkg/strings/">strings</a></dl>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/strings/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/strings/#Reader.Read"><code>Read</code></a> 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
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
+</p>
+
+<p>
+The
+<a href="/pkg/strings/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/strings/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+
+<dl id="time"><a href="/pkg/time/">time</a></dl>
+
+<dd>
+<p>
+<a href="/pkg/time/#Duration"><code>Duration</code></a>'s
+time.Duration.String method now reports the zero duration as <code>"0s"</code>, not <code>"0"</code>.
+<a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> continues to accept both forms.
+</p>
+
+<p>
+The method call <code>time.Local.String()</code> now returns <code>"Local"</code> on all systems;
+in earlier releases, it returned an empty string on Windows.
+</p>
+
+<p>
+The time zone database in
+<code>$GOROOT/lib/time</code> 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.
+</p>
+</dd>
+
+<dl id="syscall"><a href="/pkg/syscall/">syscall</a></dl>
+
+<dd>
+<p>
+On Linux, the
+<a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a> struct
+(as used in
+<a href="/pkg/os/exec/#Cmd"><code>os/exec.Cmd</code></a>'s <code>SysProcAttr</code> field)
+has a new <code>Unshare</code> field.
+If the field is nonzero, the child process created by
+<a href="/pkg/syscall/#ForkExec"><code>ForkExec</code></a>
+(as used in <code>exec.Cmd</code>'s <code>Run</code> method)
+will call the
+<a href="http://man7.org/linux/man-pages/man2/unshare.2.html"><i>unshare</i>(2)</a>
+system call before executing the new program.
+</p>
+</dd>
diff --git a/doc/go1.7.txt b/doc/go1.7.txt
deleted file mode 100644 (file)
index adac6a3..0000000
+++ /dev/null
@@ -1,32 +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)
-
-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)
-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)
index d9157c2b17c76143272b300e31580b2d47161d16..1d7df3d42c9b62792f49884dd5efb0e57d207352 100644 (file)
@@ -33,7 +33,7 @@ compiler using the GCC back end, see
 </p>
 
 <p>
-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.
 </p>
@@ -63,19 +63,19 @@ architectures.
        <code>arm64</code> (<code>AArch64</code>)
 </dt>
 <dd>
-       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.
 </dd>
 <dt>
        <code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
 </dt>
 <dd>
-       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.
 </dd>
 <dt>
        <code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
 </dt>
 <dd>
-       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.
 </dd>
 </dl>
 
index 96a7672778bb6907d378692c9bd596149a04c7ef..0e6b86fdaf5d15dce2d9b237d568bb9b1f7badbe 100644 (file)
@@ -221,7 +221,7 @@ and building a simple program, as follows.
 <p>
 Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
 <code class="testUnix">$HOME/work</code>
-<code class="testWindows" style="display: none">%HOME%\work</code>
+<code class="testWindows" style="display: none">C:\work</code>
 for example, and set the <code>GOPATH</code> environment
 variable to point to that location.
 </p>
@@ -231,7 +231,7 @@ $ <b>export GOPATH=$HOME/work</b>
 </pre>
 
 <pre class="testWindows" style="display: none">
-C:\&gt; <b>set GOPATH=%HOME%\work</b>
+C:\&gt; <b>set GOPATH=C:\work</b>
 </pre>
 
 <p>
diff --git a/misc/cgo/errors/issue14669.go b/misc/cgo/errors/issue14669.go
new file mode 100644 (file)
index 0000000..04d2bcb
--- /dev/null
@@ -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,
+       }
+}
index b6cec8e10d0fe28e087c122d6685c95aee65784a..27eb78e36cfbc0bc958ba2d08faa531365637a16 100644 (file)
@@ -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 <stdlib.h>
+                    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 <stdlib.h>
+                    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() {
index cd358a10f815e0fe13c9c8be143a4f07ee334c7f..643d03820502850015a3081aec4f7cc6db3e9433 100755 (executable)
@@ -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
index c0c45398cda9db6502c2ace5dba990274a21ade3..ab14c007a9cb5241d89083a1cd48c6765f8eefcc 100644 (file)
@@ -79,14 +79,12 @@ 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"}...)
        }
        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))
index 2aaf09b7c1961ec5d16f678996aaaf17d6020e05..353f980c50d47e3336ff66ebc0770ff3b210487c 100644 (file)
@@ -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);
index 76628abaff87410d5e976adaee5510c90e70e5a5..c30df3b6c2a5ec72f4f3dd17436e7bb94b8528cc 100755 (executable)
@@ -134,6 +134,26 @@ 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
+
+    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/tsan3.go b/misc/cgo/testsanitizers/tsan3.go
new file mode 100644 (file)
index 0000000..87f6c80
--- /dev/null
@@ -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/misc/cgo/testsanitizers/tsan4.go b/misc/cgo/testsanitizers/tsan4.go
new file mode 100644 (file)
index 0000000..f0c76d8
--- /dev/null
@@ -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 <stdlib.h>
+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()
+}
index 8c14b87f0a5299de97b578275f366114f4efca0d..8a8784c8be011c66bd11f7b653261c6cc64ec140 100644 (file)
@@ -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
index 36f4e23980930c82f55749aef4e00779527ccb5c..2a1e4321826195572f685e6435edc01c929cfc54 100644 (file)
@@ -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 (file)
index 0000000..c2c9910
--- /dev/null
@@ -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] }
index e2a2a5440e04c235ca5545198b85849085af734e..096ef082bf8764dab9ccd3684acaf53e1ceac46c 100644 (file)
@@ -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
index 944b2d49529adf7dff3bf17daae9b11cfe3a8ac4..426e4434eb75444a81e86e86bb7b07f9aaae2d8e 100644 (file)
@@ -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
                }
index 6e91d907ce96bdcb87247c15b144db96edf38288..27aa8e5dab67243fc7014333226761a836f70b40 100644 (file)
@@ -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 {
index 5ee4f88f8036ba7d9dc1be55dd70ca52263b95e6..e92d02f8a2e872ddab84503a6ea0cd4e238faa78 100644 (file)
@@ -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.
 
index d769a6aaa98d0eded670a1721d53a900f008b0cc..858048696e4ed15789c445523925b54989953566 100644 (file)
@@ -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 {
index 83826c80c417af2817a74a5d9ddeb8437886ddf1..28cfc7a97884a7d448c585f6b6d866fcfe9c914d 100644 (file)
@@ -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")
index b5c78506189e50a96bdf9af44b3543ce930aa019..7b3034d4e0d90cec3e8b001f38150a5f679e7e50 100644 (file)
@@ -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/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go
new file mode 100644 (file)
index 0000000..625e136
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 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
+}
index 24906e2cce200c5e5f218f8ba911c178e130cd2c..c9c64203ae68bdf3fc9e32cbebf27db7538e69ad 100644 (file)
@@ -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])
index 63fdcac27db84068632e6131c9046cdea7bba527..22dfe127b3db0b390006342efe5c046923e511ee 100644 (file)
@@ -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
index 3ee4461352c30d45be03044e245b4c9f22b2912e..451798244f6db2a48fd0793a74622faa96b85d92 100644 (file)
@@ -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
 }
@@ -1241,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 <<EOF\n", strings.Join(args, " "))
+               fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
                os.Stderr.Write(stdin)
                fmt.Fprint(os.Stderr, "EOF\n")
        }
-       stdout, stderr, _ := run(stdin, args)
+       stdout, stderr, _ := run(stdin, nargs)
        if *debugGcc {
                os.Stderr.Write(stdout)
                os.Stderr.Write(stderr)
index 5eab3a71b49e291938ef724ee15f93da5508f764..5d6930d3ea402ca09fd9afdefa7f7ebd4d479626 100644 (file)
@@ -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
        }
 
@@ -560,6 +570,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 +646,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 {
@@ -710,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 <stdlib.h>\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 {
@@ -817,6 +831,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 +1035,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 +1319,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*);
@@ -1346,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)
 
@@ -1360,10 +1375,8 @@ func _cgoCheckResult(interface{})
 `
 
 const gccgoGoProlog = `
-//extern runtime.cgoCheckPointer
 func _cgoCheckPointer(interface{}, ...interface{}) interface{}
 
-//extern runtime.cgoCheckResult
 func _cgoCheckResult(interface{})
 `
 
@@ -1396,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
@@ -1406,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
@@ -1415,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))
 }
 `
 
@@ -1428,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 <stdlib.h> 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)
index 2b45e5b998bc1065f0081b40dff0795ebe796123..2e77f702e353f51d307034ac2bbf625392d8bc96 100644 (file)
@@ -60,8 +60,15 @@ Flags:
        -installsuffix suffix
                Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
                instead of $GOROOT/pkg/$GOOS_$GOARCH.
+       -l
+               Disable inlining.
        -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
index 461ef2ada1bb3299222f5278baa44925378985a7..42915340a06bf8d6067114919226aaf90ef3e4a4 100644 (file)
@@ -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
index f862e8a92ba9bb91f471a75bfdd552a9d0a0c66a..5d9070ca130c0d89671963023c680e41af3eacda 100644 (file)
@@ -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))
 
                /*
index 764f5c3a9e63802b1f9370ec5cd56357c92d71e2..77720c855f13f17156827530ef5456102fdc5ea4 100644 (file)
@@ -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))
        }
index 54d878d92bd0afb6a197f28300661a4e97e41d1f..756bcec75c88ee3e641d6ad49e6682235772976e 100644 (file)
@@ -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.
index 9ac999167e1dbb75eb76ccde5ed0b90d6935cb28..b5d7bc05c405e4d37302e35b38b088feae5cb291 100644 (file)
@@ -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
index 81230413182f4c5e99f0d7a490817f272f040189..2b62405544d6971a2a0bdfe0fc03ae342fdd448e 100644 (file)
@@ -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/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go
new file mode 100644 (file)
index 0000000..469f086
--- /dev/null
@@ -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\\),"},
+       },
+}
index 5d037ae05e74d12b636f65bf2671a63254b90cd8..f533053cd74acc2aaf0263c8df26e6336cb26432 100644 (file)
@@ -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
@@ -125,6 +162,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 +207,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 +218,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 +643,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?")
@@ -909,7 +974,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
@@ -1012,6 +1077,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 {
@@ -1088,6 +1155,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
        }
@@ -1117,15 +1194,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 ONAME
                        p.op(ONAME)
-                       p.bool(true) // indicate blank identifier
+                       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
                }
@@ -1134,24 +1209,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)
+                       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
-
-       case OPACK, ONONAME:
-               p.op(op)
+               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) {
@@ -1160,14 +1229,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)
@@ -1176,16 +1245,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:
@@ -1198,9 +1263,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:
@@ -1231,26 +1293,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:
@@ -1306,7 +1377,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)
        }
 }
 
@@ -1336,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.
@@ -1370,10 +1442,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)
@@ -1382,9 +1451,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)
@@ -1420,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
+               // nothing to emit
 
-       case OLABEL:
-               p.op(OLABEL)
+       case OGOTO, OLABEL:
+               p.op(op)
                p.expr(n.Left)
 
        default:
@@ -1475,6 +1542,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 {
index 6b0593cd472fc450ba4fb5aa842a5c40f1a06e35..36aa0e8b9ceaf36a5a18bd7c9316d93b47589629 100644 (file)
@@ -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
 
@@ -24,10 +25,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 +61,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 ---
@@ -100,7 +104,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
@@ -230,7 +236,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
@@ -331,7 +337,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 +397,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() {
@@ -788,16 +802,11 @@ 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 OPACK, ONONAME:
                return mkname(p.sym())
 
+       // case OPACK, ONONAME:
+       //      unreachable - should have been resolved by typechecking
+
        case OTYPE:
                if p.bool() {
                        return mkname(p.sym())
@@ -810,12 +819,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)
@@ -827,18 +833,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
 
@@ -854,14 +857,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
@@ -891,29 +887,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
@@ -1053,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)
@@ -1063,23 +1049,32 @@ 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:
                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
        }
 }
index cc64e73f25c1e30061053c4314396bb2973f83fc..b9010f4366dcce491133187a396ae9b7d1711bbb 100644 (file)
 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"
index fd57fbd4a7958b74b88518dd5459fffc2e28d5f4..dbefcc7a0bb52db0a95e884345c6351ba2940087 100644 (file)
@@ -518,8 +518,7 @@ func cgen_wb(n, res *Node, wb bool) {
        case ODOT,
                ODOTPTR,
                OINDEX,
-               OIND,
-               ONAME: // PHEAP or 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&PHEAP == 0 && 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&PHEAP != 0) || 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.
index 04fa250985851880068e897976c2f0bb6503a7db..ecdf19a2c4293a4997c09ef8b20e9c59483ee160 100644 (file)
@@ -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)
@@ -303,7 +332,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
@@ -313,7 +342,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/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go
new file mode 100644 (file)
index 0000000..118183d
--- /dev/null
@@ -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)
+       }
+}
index 9bb202752064f2ce19ea9b1a27f167949c037fcb..96a1dfb3c26abf20016d4e87d19acdb9e94cb1f4 100644 (file)
@@ -405,7 +405,6 @@ func Complexgen(n *Node, res *Node) {
                ODOTPTR,
                OINDEX,
                OIND,
-               ONAME, // PHEAP or PPARAMREF var
                OCALLFUNC,
                OCALLMETH,
                OCALLINTER:
index ba5b6b689cab014d6de8da4d9f311565a739ffaf..a4b98ec7c5219abd31586f0ed945c6059b260e90 100644 (file)
@@ -385,32 +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 = PPARAMREF
+                       c.Class = PAUTOHEAP
+                       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
@@ -504,10 +508,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
@@ -534,11 +536,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)
@@ -671,6 +669,18 @@ 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.
@@ -680,9 +690,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
        }
@@ -827,14 +836,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 {
@@ -1025,9 +1034,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())
 
index bc22dfacc0f71314fa928e865dffe4982b15acc8..d7365daaea3ab6e011dbb1c2c57183d191365cb3 100644 (file)
@@ -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)
@@ -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
@@ -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,
@@ -1818,14 +1817,14 @@ 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.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:
@@ -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 {
index 2dd137ed773c44cb39effd8102b3baa187bbe40f..1148b27f025f1792bfeab6172beb8e7574a4f2a5 100644 (file)
@@ -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:
index 82b84b3aa52f283ef83b00bdc6a0c8b2737d5cb6..3d26a1d89b3029b13d84f9301c727249e372c953 100644 (file)
@@ -218,9 +218,9 @@ var classnames = []string{
        "Pxxx",
        "PEXTERN",
        "PAUTO",
+       "PAUTOHEAP",
        "PPARAM",
        "PPARAMOUT",
-       "PPARAMREF",
        "PFUNC",
 }
 
@@ -251,14 +251,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 +794,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
                        }
@@ -1197,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()
@@ -1663,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)
@@ -1696,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)
        }
 
index 275e6a750713a7d67d77dd1baf354100251dc318..3faf6d4a63cc9c28eef7ffb898d5d30a60f06def 100644 (file)
@@ -43,52 +43,38 @@ func addrescapes(n *Node) {
                        break
                }
 
-               switch n.Class {
-               case PPARAMREF:
+               // If a closure reference escapes, mark the outer variable as escaping.
+               if n.isClosureVar() {
                        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 +91,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 +333,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 +346,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 {
                        gused(nr)
                }
 
@@ -908,11 +991,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
index f9a372dccee63d8eff9f289ab42f8b7c2fd75793..b6b858c0d980c86c3c3c78b50b8b1c50450d5779 100644 (file)
@@ -91,14 +91,12 @@ 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
@@ -133,6 +131,7 @@ var pragcgobuf string
 var infile string
 
 var outfile string
+var linkobj string
 
 var bout *bio.Writer
 
@@ -260,8 +259,6 @@ var Widthreg int
 
 var nblank *Node
 
-var Funcdepth int32
-
 var typecheckok bool
 
 var compiling_runtime bool
index 603d0349d601b7a8b408ed9023d5475f9b157348..4943d9dddeda49eb27f0692d3dfc5dc962f8ffce 100644 (file)
@@ -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")
@@ -528,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).
+//
+// 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).
 //
-// 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 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
@@ -559,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
@@ -577,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 __,
@@ -589,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
 }
 
index 6c9223b57a1b250c0728113df97c9abb1961991e..67a050a9cad1363a8ea7bbebf7ddf29995352809 100644 (file)
@@ -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
-//                     <pkg>.init()                    (7)
-//             { <init stmts> }                        (8)
-//             init.<n>() // if any                    (9)
-//             initdone· = 2;                         (10)
-//             return                                  (11)
-//     }
+//              }
+//              if initdone· == 1 {                     (4)
+//                      throw()                         (4a)
+//              }
+//              initdone· = 1                           (5)
+//              // over all matching imported symbols
+//                      <pkg>.init()                    (6)
+//              { <init stmts> }                        (7)
+//              init.<n>() // 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)
index 95ba56edd2288ce0b36fe9ab9ad6bb715fcfdde3..0c1b05079c511f92a71dc1def73c31e44860f0f7 100644 (file)
@@ -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/logic_test.go b/src/cmd/compile/internal/gc/logic_test.go
new file mode 100644 (file)
index 0000000..78d2dd2
--- /dev/null
@@ -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)
+                               }
+                       }
+               }
+       }
+}
index 54211e4892ddefc79ea021fd22e32c44679ee159..8ad3300dbed3e249f63f77c6e3cc5f10a329f37a 100644 (file)
@@ -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()
                }
 
@@ -783,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
index eb0e6681fa895da17cbed7b86d6e17ea231104af..58cbd240d2758422714b0fe5f552a1d2d4c0b6a8 100644 (file)
@@ -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 (
index ae23f9557410a3a2c4ea7a268b270693442bdb59..b5c06d165d4c6d23c0fc1eb5eeab37c4b7a2f112 100644 (file)
@@ -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 != "" {
index 015baa2376a1b60a6c059549a10a2fcabd92774e..bcdae6c76272e4d3dd0442aeb4254e0ada68d77f 100644 (file)
@@ -76,7 +76,6 @@ var opnames = []string{
        OINDEX:           "INDEX",
        OINDEXMAP:        "INDEXMAP",
        OKEY:             "KEY",
-       OPARAM:           "PARAM",
        OLEN:             "LEN",
        OMAKE:            "MAKE",
        OMAKECHAN:        "MAKECHAN",
index 7026ad79efa383caf6b33a102c7ef6a21ff7b5dd..da334a1558cfd4c5d9bf97eb27e3830e02c6a034 100644 (file)
@@ -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)
index 55f352590bb35100e3a3fc7fff4f674f421e20cf..7ffd42f83cba51f6667ebd51877df317c4fe01cf 100644 (file)
@@ -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()
index 87f4a11c0077c33e757f5024ea37c30a99b61a03..85138c9fcde140c7f856144eb9bc2fdb0b48814c 100644 (file)
@@ -197,54 +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.
+// 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)
+}
+
+// getvariables returns the list of on-stack variables that we need to track.
 func getvariables(fn *Node) []*Node {
-       var result []*Node
-       for _, ln := range fn.Func.Dcl {
-               if ln.Op == ONAME {
-                       // In order for GODEBUG=gcdead=1 to work, each bitmap needs
-                       // to contain information about all variables covered by the bitmap.
-                       // For local variables, the bitmap only covers the stkptrsize
-                       // 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.
-                       //
+       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.
@@ -567,9 +554,11 @@ 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:
-                               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.
@@ -593,7 +582,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))
@@ -607,24 +596,17 @@ 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 {
-                       case PAUTO, PPARAM, PPARAMOUT:
-                               pos, ok := from.Node.(*Node).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 ((from.Node).(*Node)).Addrtaken {
+               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 {
                                        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)
                                                }
                                        }
@@ -635,17 +617,10 @@ 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 {
-                       case PAUTO, PPARAM, PPARAMOUT:
-                               pos, ok := to.Node.(*Node).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 ((to.Node).(*Node)).Addrtaken {
+               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)
                                        }
@@ -665,7 +640,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)
                                                }
                                        }
@@ -675,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.
@@ -812,8 +805,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
                }
        }
@@ -980,23 +972,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.
index 5bcaf89d50173aa92f4280e7e75f9479806815c9..4a658b197665e9fc0a474c31fdf216e7121d788c 100644 (file)
@@ -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 == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
                hascalls := 0
                foreach(n, hascallspred, &hascalls)
                if hascalls != 0 {
index c6f2acffbfcbb1035d1a058539e00f5b731ff226..4469d71f1c56ccc4beb606348e984eb6cd6a19b0 100644 (file)
@@ -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
 }
 
 func litas(l *Node, r *Node, init *Nodes) {
index a01da13883e5a9c95a24504e533753070647b1c0..c474c47ddbdcedf54f27f6d9c836b5cf5c250097 100644 (file)
@@ -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/sparselocatephifunctions.go b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
new file mode 100644 (file)
index 0000000..e15f221
--- /dev/null
@@ -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())
+}
index e824b476e1a9ab271075ad7ffcbe8ae1528185ab..ecff7c07dea5932da3ac84d5b769d838c3329979 100644 (file)
@@ -161,23 +161,19 @@ func buildssa(fn *Node) *ssa.Func {
                                // the function.
                                s.returns = append(s.returns, n)
                        }
-               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.
+                       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:
                        // 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])
                }
        }
 
@@ -218,8 +214,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{}
@@ -282,9 +286,13 @@ 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
+       // 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
@@ -577,24 +585,9 @@ 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)
-               }
-
-               // 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
+               if n.Left.Class == PAUTOHEAP {
+                       Fatalf("DCL %v", n)
                }
-               r := s.expr(palloc)
-               s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0)
 
        case OLABEL:
                sym := n.Left.Sym
@@ -980,8 +973,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())
@@ -990,6 +982,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()
@@ -1428,9 +1430,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
@@ -2644,6 +2643,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.
@@ -2724,10 +2727,8 @@ 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:
-                       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:
@@ -2770,17 +2771,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
@@ -2808,12 +2798,14 @@ 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?
+       case PEXTERN:
                return false
        case PPARAMOUT:
                if hasdefer {
@@ -2993,6 +2985,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 {
@@ -3743,7 +3740,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,
@@ -3758,13 +3756,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
@@ -3803,6 +3801,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))
        }
 
index 8a233eafe0d6d7d5d330c893c2e0ff270d2c1804..c89917df88c2685ab577bdc38948db5b2d368983 100644 (file)
@@ -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") }
index 3ce8bd16d2d5eb6751e99a293b99b663344d2b43..c2abff7b63487b7dc2c56147018a2fcdf437594d 100644 (file)
@@ -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...)
 
@@ -1224,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 == PAUTOHEAP {
                        ul++
                }
                goto out
@@ -2250,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)
index 8a675ac1579881f7efb70eb3bba83e81ec240397..e673db9004804c5502c81c42f30c6ac1494487bd 100644 (file)
@@ -68,11 +68,48 @@ 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
+       isClosureVar
+)
+
+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&notLiveAtEnd != 0
+}
+func (n *Node) SetNotLiveAtEnd(b bool) {
+       if b {
+               n.flags |= notLiveAtEnd
+       } else {
+               n.flags &^= notLiveAtEnd
+       }
+}
+func (n *Node) isClosureVar() bool {
+       return n.flags&isClosureVar != 0
+}
+func (n *Node) setIsClosureVar(b bool) {
+       if b {
+               n.flags |= isClosureVar
+       } else {
+               n.flags &^= isClosureVar
+       }
 }
 
 // Val returns the Val for the node.
@@ -117,18 +154,18 @@ 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
-       Heapaddr  *Node // temp holding heap address of param
-       Inlvar    *Node // ONAME substitute while inlining
-       Defn      *Node // initializing assignment
-       Curfn     *Node // function for local variables
-       Param     *Param
-       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
+       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
        Funcdepth int32
        Method    bool // OCALLMETH name
        Readonly  bool
@@ -141,16 +178,83 @@ 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
+       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
+       // ONAME closure linkage
+       // 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.
@@ -162,9 +266,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
@@ -266,7 +369,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/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
new file mode 100644 (file)
index 0000000..eea6165
--- /dev/null
@@ -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)
+       }
+}
index 9ae05f7ff1f1a5e5b7af11dd3ac0ffb6168e0fcf..ab13df6eba598118d51ae4bea1739286b2a3f913 100644 (file)
@@ -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 {
index 7fccbe1a52b945b39d9db5436c7523fb6e69738e..c8ee9417e611f6f7e80d0228a1ae23008bf49402 100644 (file)
@@ -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
@@ -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:
@@ -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
                }
        }
 
@@ -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
        }
 
@@ -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
index 84df22502fff93b677d3a9b9801ffd0d4e88ccac..b55af7e25a0a7b4ac8fcdd26d5a1f9c0a3db7c6e 100644 (file)
@@ -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})
index 14784e284e93dada9f8c6124c5f3a5760c07e8b3..66eb7e97ac6c6dc0a2d2dfbd4fae6586e9f2ab94 100644 (file)
@@ -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,9 +647,7 @@ opswitch:
                n.Addable = true
 
        case ONAME:
-               if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
-                       n.Addable = true
-               }
+               n.Addable = true
 
        case OCALLINTER:
                usemethod(n)
@@ -1640,7 +1659,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))
@@ -2515,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
@@ -2550,41 +2569,31 @@ 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() {
-               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 {
+               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))
                }
 
-               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 +2606,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
@@ -2612,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())...)
index 864fd76d121f9e73143121839930a97a7c75ee99..eb56d8b82e6e9319265206ba3c5b1a7fd20b0db7 100644 (file)
@@ -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)
                }
 
index 60be3de5218ad944ecba6f30670b36359ff5553b..bfedd477946b5322d254e7f7f4ac5cb80b9c0b7b 100644 (file)
@@ -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
index bc9c830ee958aa5b48c9798d79ad151eb590bac1..b3c7544ad129ab22aa1aa44f798adb0805c43385 100644 (file)
@@ -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
index 26f16bae580b3dc9fa351c2f10e372ca150cd936..ddb58d9f79b92c166a2fd2ad221401927d2ab839 100644 (file)
@@ -9,23 +9,25 @@ 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
-       flagRegMask  regMask                    // flag register mask
-       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
+       flagRegMask     regMask                    // flag register mask
+       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, ...
 
@@ -162,10 +164,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.
@@ -262,3 +281,7 @@ func (c *Config) DebugHashMatch(evname, name string) bool {
        }
        return false
 }
+
+func (c *Config) DebugNameMatch(evname, name string) bool {
+       return os.Getenv(evname) == name
+}
index 8cc0db1d17266eabdfbe40d8a98b9da26a173857..ad4e4161591d0ada2ca49b03544bbd306d61e8ac 100644 (file)
@@ -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
                                }
                        }
@@ -190,7 +187,7 @@ func cse(f *Func) {
                }
        }
        if f.pass.stats > 0 {
-               f.logStat("CSE REWRITES", rewrites)
+               f.LogStat("CSE REWRITES", rewrites)
        }
 }
 
@@ -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
+       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)
 }
index 78ba2e9e1b6aae230b77597ba54fd0a09f33bc47..0c532c87ff721120503b0307f843bc63770f8d6f 100644 (file)
@@ -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:
index 2c7a8a1f11e1fc1aca815d69b6e40d3678086efc..1d60bb606ad226101c57c95de5757e9a22f671a2 100644 (file)
@@ -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.
index 8c40c77f06d5cbd738f7635ece77a1e11520a727..94650141949c8be6250eed382a5ef1547a82772d 100644 (file)
@@ -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
index fcabdb1dd908d94b2b9bc935fbffd47ae78add89..0fc5749f1d5aa61e6063f3c792106b591d6ffcf8 100644 (file)
@@ -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")
 
index 3f03943a7418d9bff7f6ef500de04766452da6a9..cb2d82f3527640cd39164de0158b269d240b3699 100644 (file)
@@ -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")
                }
index af0ee4cccf07299354ff4b2d8bed887c8fba2c92..e271ed4ef6b9abd865a2c56dceaa5b889e5937c6 100644 (file)
@@ -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()
index 558d041624a1310f647e5e6306da0858dfef2aa7..fc8214b9d9263e470955c4c07c15220c05879431 100644 (file)
@@ -674,6 +674,7 @@ const (
        OpVarDef
        OpVarKill
        OpVarLive
+       OpKeepAlive
 )
 
 var opcodeTable = [...]opInfo{
@@ -6167,6 +6168,7 @@ var opcodeTable = [...]opInfo{
        },
        {
                name:    "FwdRef",
+               auxType: auxSym,
                argLen:  0,
                generic: true,
        },
@@ -6193,6 +6195,11 @@ var opcodeTable = [...]opInfo{
                argLen:  1,
                generic: true,
        },
+       {
+               name:    "KeepAlive",
+               argLen:  2,
+               generic: true,
+       },
 }
 
 func (o Op) Asm() obj.As    { return opcodeTable[o].asm }
index 8dff17a5b413fb11a60170ceb31764b4fba31780..87069abc3b1b9f79d9e89e4c202eac82ed23f142 100644 (file)
@@ -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++ {
index 17ef5e461a9849c78189c4141703015227994fda..4416fa2cf37698be7896fe9428d4b76c80c6a5e4 100644 (file)
@@ -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 (file)
index 0000000..ae1ec35
--- /dev/null
@@ -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 (file)
index 0000000..6d72a3e
--- /dev/null
@@ -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})
+}
index e0dc1009afff1b7b3e46e953b07f6196fe20157b..8603615f251720f54a1f98ad467f240843717300 100644 (file)
 package ssa
 
 import (
-       "cmd/internal/obj"
        "fmt"
        "unsafe"
 )
@@ -456,7 +455,7 @@ func (s *regAllocState) init(f *Func) {
        s.allocatable = regMask(1)<<s.numRegs - 1
        s.allocatable &^= 1 << s.SPReg
        s.allocatable &^= 1 << s.SBReg
-       if obj.Framepointer_enabled != 0 {
+       if s.f.Config.ctxt.Framepointer_enabled {
                s.allocatable &^= 1 << 5 // BP
        }
        if s.f.Config.ctxt.Flag_dynlink {
@@ -941,11 +940,29 @@ 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)
+                               } 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.Op = OpCopy
+                                       v.SetArgs1(v.Args[1])
+                               }
+                               b.Values = append(b.Values, v)
+                               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
                        }
 
@@ -1311,20 +1328,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))
                                                                }
                                                        }
                                                }
@@ -1524,7 +1546,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")
        }
 }
index 7d6d2179f7642592ff024a83827d90fcb2aebbf2..03c38827cc433ea9c2b9966a2615873269804f9f 100644 (file)
@@ -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
index 0211a70f09d2117db359736219020ec7550b5141..afb9f6049186cc7368d24054bdd3aafb32d92457 100644 (file)
@@ -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
index 66bebf139e66bfe2f6d755c45844374e9f0e0a0c..b5cabfb0cdf0835e4e9b9529531660030c02c9db 100644 (file)
@@ -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
index 45c78974963cdf5060b2ca39951fee5e8322873e..7c82a60d0fa8fc1e26e4660e4370e4d4ca59645e 100644 (file)
@@ -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
        }
@@ -134,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
 }
diff --git a/src/cmd/compile/internal/ssa/sparsetreemap.go b/src/cmd/compile/internal/ssa/sparsetreemap.go
new file mode 100644 (file)
index 0000000..6127698
--- /dev/null
@@ -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)
+}
index c08ed79cd65fe9051483819fbe4612a1e604be5d..83f65d093b7c5c4f2d9fce10b6e39f968352d29d 100644 (file)
@@ -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")
index f432cd8933f93d6982f35be3ca62d03e2aa361da..6406326b60e0501cf13f06cfd61b8b726b8ce9c0 100644 (file)
@@ -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)
@@ -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
index 46495950e98f53c57ae72d9ff6bbbea7a13da5cd..a9ed66eea06cd5a5eb22bbbb02c29d0df54cddfa 100644 (file)
@@ -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
index 04a13b2365ce6ab89e684754300af9821dc65fc6..aa12aa9dc3da8c0e048b1cd582ba99118d93b930 100644 (file)
@@ -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},
 
index 2b68fc222460c89333b4a03d79c4c0ca7bd498bc..c367c70b043089c72f2a52cadb6a8933b7bc19ed 100644 (file)
@@ -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{}
index 3d123c2c8641dad158f09598c0c6c0fbcbddd358..1a1f7d961bea77aa31b6073bacca7f5d90d4a722 100644 (file)
@@ -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
        }
 }
index 2b74cb59e35c58fa53da34c17c1ab09c5f018c16..2a64657732067ccb2f706f84b148428828bec883 100644 (file)
@@ -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
index 0102b5e08a227273934c35d705b9fc3e29976e86..e0cb216b8c4e5605f0e817aff95a905cdaa621d4 100644 (file)
@@ -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"
                }
@@ -669,6 +672,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"
        }
@@ -3097,6 +3106,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
 }
index ac82b2ffeb467b8333c013526691a3d746f49e05..50e6b500dab3d781877568bbac62d1c81d927b80 100644 (file)
@@ -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() {
@@ -1177,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 {
@@ -1192,11 +1166,38 @@ 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)
 }
 
+// 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 {
@@ -1216,7 +1217,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")
 
@@ -2832,7 +2832,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) }
@@ -2841,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()
        `)
index ada8ddded47f2878990d7c86e37dd2b4846e8a22..fae9536d13fb936bcfef43e6f70c4cfcc97ebf9d 100644 (file)
@@ -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
                        }
index 02abcbe23a07f063fe761465728b5baa63655962..bc5982e61ce9cf7f5652b89381eafabe237dbfcd 100644 (file)
@@ -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.
 
index 4ff71f216831252f454ad64d4d7b3f364d367a46..10b8cf8c49dcfa39b446c52b01d403d86f611489 100644 (file)
@@ -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)
@@ -848,6 +848,15 @@ var vcsPaths = []*vcsPath{
                repo:   "https://{root}",
        },
 
+       // Git at OpenStack
+       {
+               prefix: "git.openstack.org",
+               re:     `^(?P<root>git\.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.
        {
index d951189459870482d94a7dbc725d8542b43a329d..06650608ba40a84f0e15743c12a93c8d39b6d1f1 100644 (file)
@@ -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",
index 69fa496110db43b4073e3ca4d1a238d7b624bb35..214f65cbc4cbdfb43b08e9719b90b0d5fa291aa2 100644 (file)
@@ -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)
                }
index 484bb472d09e167cf85054205369fbc8d134a25d..1852dc74f63b7d4e0f014932d38c9d8f87316210 100644 (file)
@@ -13,7 +13,7 @@ import (
 // go-specific code shared across loaders (5l, 6l, 8l).
 
 var (
-       Framepointer_enabled int
+       framepointer_enabled int
        Fieldtrack_enabled   int
 )
 
@@ -26,14 +26,21 @@ var exper = []struct {
        val  *int
 }{
        {"fieldtrack", &Fieldtrack_enabled},
-       {"framepointer", &Framepointer_enabled},
+       {"framepointer", &framepointer_enabled},
 }
 
 func addexp(s string) {
+       // Could do general integer parsing here, but the runtime copy doesn't yet.
+       v := 1
+       name := s
+       if len(name) > 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
index eaf702533a141fea9d8ec0dc13983cf5a5ccb2fa..b6861f4c1e572c7b112ea61c2c685928688c1c1d 100644 (file)
@@ -664,6 +664,8 @@ type Link struct {
        Etextp        *LSym
        Errors        int
 
+       Framepointer_enabled bool
+
        // state for writing objects
        Text []*LSym
        Data []*LSym
index 6f3542b3d4f42102ad6453088b63acc814783264..e974ca8c8af30602c7b39780fb46d2af20ff9866 100644 (file)
@@ -106,6 +106,7 @@ func Linknew(arch *LinkArch) *Link {
        }
 
        ctxt.Flag_optimize = true
+       ctxt.Framepointer_enabled = Framepointer_enabled(Getgoos(), arch.Name)
        return ctxt
 }
 
index 294cedcb0a25a3512a9f446c09836f1c098fb258..18813c35a8ea3ecb173e33204e5511c3d3d5e805 100644 (file)
@@ -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()
index f00e4afdb8f7ac363d136b3259e15a5664e78143..ab1dabc2b89735959662c1c67f725dd6217928d4 100644 (file)
@@ -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
index e3fef54e7175105ac39a94b6f13d2bfa01065a1e..3b30154625843141878d9ff792f2c83ba484b77e 100644 (file)
@@ -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",
index 8605980b94d9960e798ad57221a0f62dcea5408a..414a4d34a558c58d0c90bb8fce38761f3e5f2192 100644 (file)
@@ -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)
@@ -3687,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
@@ -3706,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)
index df774437ac51dc9331b4bcb91253db833e374c27..5dad0bbb982616d921cd15d254d7544f2e298eb4 100644 (file)
@@ -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 && 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.
                bpsize = ctxt.Arch.PtrSize
-
                autoffset += int32(bpsize)
                p.To.Offset += int64(bpsize)
        } else {
index d63f8f616f189e6d38c78d84a2a1daccabecb16e..25c3301ab88805b7a6bd0cdf1a1b0c028c352a0f 100644 (file)
@@ -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.
index 5018c02af185e78caebfb0b5202e1293bd76f113..5dfbbd4a5dc8acc75e9bf7cacc5541b88f09f952 100644 (file)
@@ -197,6 +197,7 @@ func makeVizTmpDir() error {
        if err != nil {
                return err
        }
+       tempfile.DeferDelete(name)
        vizTmpDir = name
        return nil
 }
index c492b752b96fbb66271aaa4f644ef3500974b729..b11ad2ab3606e7333926d47a0c449bde70f505e8 100644 (file)
@@ -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)
index 31c117690a1c1f2a2112e285c083d1f63d4230c3..a5706345e4395423463c7e62ba086252abfd7dbd 100644 (file)
@@ -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()
index bf1a7e74c1403f24c0c3443c150df09cf59c1d5a..01747c543017a742608a42f6c1a938614fdac801 100644 (file)
@@ -1558,6 +1558,12 @@ func writelines(prev *LSym) *LSym {
                                if !haslinkregister() {
                                        offs -= int64(SysArch.PtrSize)
                                }
+                               if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
+                                       // The frame pointer is saved
+                                       // between the CFA and the
+                                       // autos.
+                                       offs -= int64(SysArch.PtrSize)
+                               }
 
                        case obj.A_PARAM:
                                dt = DW_ABRV_PARAM
index e66de49f4133735977587ab37ad7d8cd2e438058..39d3609a291f04546a81135320c86a5ae06ec659 100644 (file)
@@ -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
index 425c75571fee81040ae6c0895894c1785c78e364..79cdae0aee898c230c0266d1071083a4aa747fa8 100644 (file)
@@ -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')
index 4fff35c38e0633f27322f720d60aa04292794113..bab71fb311437633bbfcb921f0713ae9cef5649e 100644 (file)
@@ -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.
@@ -1137,6 +1143,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)
+                               }
+                       }
                }
        }
 
index d16431ddaa29adc19baf977ad2bf638508c629d3..be9832dc45483031e7a489af5356b32fa2cae830 100644 (file)
@@ -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 {
index 5be42555d08118daa87f00a00c46f3c3c97dbeef..1c168f946bd04ed4701e5561d6b08ed4611b01c4 100644 (file)
@@ -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)
        }
index 2735bf13ea23e99d816c239c438c0317f38cf774..893719edbf8fdc3cabc98350a686416d6a544cb0 100644 (file)
@@ -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(`
 <html>
 <body>
-<a href="/trace">View trace</a><br>
+{{if $}}
+       {{range $e := $}}
+               <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
+       {{end}}
+       <br>
+{{else}}
+       <a href="/trace">View trace</a><br>
+{{end}}
 <a href="/goroutines">Goroutine analysis</a><br>
 <a href="/io">Network blocking profile</a><br>
 <a href="/block">Synchronization blocking profile</a><br>
@@ -132,7 +160,7 @@ var templMain = []byte(`
 <a href="/sched">Scheduler latency profile</a><br>
 </body>
 </html>
-`)
+`))
 
 // startBrowser tries to open the URL in a browser
 // and reports whether it succeeds.
index 7782a5efc8dd3313b660eeb709b63b0d1211a387..2b6a37bfd8dbcb89c57314bf3e078ce3f822e733 100644 (file)
@@ -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}})
 
index 07499e6ae6bc6ab6f30ffd528e95ec8ca1dcc582..f4b985cfbdc4611b5d2c2206b439c42fd560348f 100644 (file)
@@ -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
index cf56802cdbb249a05d01b9457015c12e62b687bb..d49f46862758716e77669755a43f798b94926a18 100644 (file)
@@ -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{}
+}
index 261ee788c7b0d025e5ea6d8c312a555f4bc63c62..ab97256c0882986253ff27e5271aae7496d1280a 100644 (file)
@@ -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
+}
index b336278c07d0158efea45ea828f86b01c93b9f48..b0a16ce18b98d637063eb3d9ff843466999f9cf9 100644 (file)
@@ -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)
+                               })
+                       }
+               }
+       }
+}
index 7967cd739c5862d019e5d080e3523efc4a5747c2..21cd0b22eef5fe6e6185635f74de712c82b59fd9 100644 (file)
@@ -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.
index 926bae88c70bdae2803b759bb6f4e9c1abb315e6..7e640692f3f265376f5383f6b41b88563f764308 100644 (file)
@@ -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() }
index c3a5c3a0aaacdf3bfce7fbbf111786cb9310e98a..6b9f9a3da7035ddc80203c5b4730bc0f5d93eda0 100644 (file)
@@ -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))
+                       }
+               })
+       }
 }
index 66d761727f481d81dabf05348d27ee0bddd95bf1..4979f8b35211397dddaa3d8d2b665e5967b457c8 100644 (file)
@@ -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)
-}
index 30535fd980e55bb180d57c05c701c36eec9b0415..2efa1930354585aaa02367b37c1e9025457abae6 100644 (file)
@@ -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
index 4d8bfc2bf0791bd6148420e374e306e1a0dd3beb..e3bfe53a4981fad9950aed2dba320227b5c39be5 100644 (file)
@@ -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)
 
index 9ff19503b203adeb46786b1d5b561a00b6719bef..169db74f57ffe0fead6a154ac4b81c1abda92498 100644 (file)
@@ -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.
index 99456b188d2a6562ebc9b9ddf433995d97e29571..90e78e57ecc42e83623587c5c8dc9a2204ea3df0 100644 (file)
@@ -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")
+       }
+}
index f6cc38650610ad23fa474df2a913eabbb5ef106e..9abe782bca54aec85416bb8a72ea64127b934adb 100644 (file)
@@ -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() {
index e63bd8669ef443087afd1f4099e7cea36af197b2..288e366a882de237da907f6a4025ad910346eb95 100644 (file)
@@ -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 {
index 5e588b92582bbc18e1cfd27b461491c6270955e6..fc25fd74a78ce7285bcdf96972fcdbdd577e7888 100644 (file)
@@ -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")
+}
index e96933e0c5566723238bee11ce4672d6b877948f..66b7cf8dc512a4948ab68a1bce75834377e93573 100644 (file)
@@ -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
diff --git a/src/crypto/sha1/issue15617_test.go b/src/crypto/sha1/issue15617_test.go
new file mode 100644 (file)
index 0000000..98038e5
--- /dev/null
@@ -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])
+       }
+}
index 9202e682a8f9b970325d655b7efcc84c7c710a1d..214afc51e1fa6466b07701f46cb3ae38e06a8db0 100644 (file)
@@ -19,6 +19,7 @@ type sha1Test struct {
 }
 
 var golden = []sha1Test{
+       {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"},
        {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
        {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
        {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
@@ -93,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)
+               }
        }
 }
 
@@ -120,6 +123,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 (file)
index 0000000..fd85a42
--- /dev/null
@@ -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 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 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)
+       }
+}
index a504e147512c73cdbc075b9417b8a4022b59b3cd..0cdb43b422fdcccaaf3b1e03fe86723990fbb9fa 100644 (file)
@@ -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 <ilya.albrekht@intel.com>
+// Maxim Locktyukhin <maxim.locktyukhin@intel.com>
+// Ronen Zohar <ronen.zohar@intel.com>
+// Chandramouli Narayanan <mouli@linux.intel.com>
+
+
 #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
index a85b74b878717419e88cbda37cfdcc34785a0c34..6d2d073d13733157422f2e0cd2b180d6ae1c0537 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 amd64p32 arm 386 s390x
+// +build amd64p32 arm 386 s390x
 
 package sha1
 
index c9f134c1069082977e79a88f036e9ae30d2ce44c..6ab3b52d65e16336b5036f26207d9b9296160d33 100644 (file)
@@ -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 <james.guilford@intel.com>
+//     Kirk Yap <kirk.s.yap@intel.com>
+//     Tim Chen <tim.c.chen@linux.intel.com>
+
 // Wt = Mt; for 0 <= t <= 15
 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
 //
        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
index c4f8b0816b0b00bed34e3b2c39a5d05c69982dd2..40c17440d652dc694d057a114d787447aeec3319 100644 (file)
@@ -76,9 +76,10 @@ 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 int64
+       // 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
@@ -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
@@ -788,7 +789,18 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
                }
        }
 
-       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
index 8334d90839cdedc6f44faadfb3aa34e674015d90..4e4bbc95e86d24e558c36dad1de1d2da62615ecf 100644 (file)
@@ -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 {
index 8e94f2143acbc4763926f2658d25241bdca10306..cf617df19f5c0023d173fc6120718a76898de151 100644 (file)
@@ -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
        }
 
index fba81f619a6fe7f31cb10e503bb21b3a63b6d6b2..d878f9988949d783014e799a0dacb85a1b69d797 100644 (file)
@@ -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.
 
index 0be0b42912eeff660bf8957f377544679ca22ddf..25dc386f53c8c9aee09011a36ea2f22608e7ec06 100644 (file)
@@ -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 {
index 1a33658a1e365b9f85d432025ddd30898db95148..894d7e82ab75c4d2b9d96bd67317cd3b68dd61e1 100644 (file)
@@ -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,156 @@ func (w *changeImplConn) Close() error {
        }
        return w.Conn.Close()
 }
+
+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 < 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 < 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()
+
+       N := b.N
+
+       var serr error
+       go func() {
+               for i := 0; i < 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 < 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")
+                       })
+               }
+       }
+}
index f067cd7cf432fcd134400d569e94c8531a1f0491..0e2fb357ee904034b46e96f8f06094bce2fad5b6 100644 (file)
@@ -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;
 }
index 6004d5cd239d18cd683ac472b9c10965107d0b72..9e6d67df55fc94595c4315c3dfffa1d3a3313b63 100644 (file)
@@ -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.
 //
index 2fe6febb26b024d9723da6b0689c0d4650664677..b189219a556a21e8327f9e0869ac5255ff18f62a 100644 (file)
@@ -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)
index 4dac6d1b2973c561b6900e309574edaaea5e813f..eab437318d6d3e3ee6513884df7120551ff6dae8 100644 (file)
@@ -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
index 1a780bf121ac4c9637d51efa73a2f40557e747ce..9f82e31ae4170ad1c21e9bcf1c98518dad8a1132 100644 (file)
@@ -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
index c8fa9a0b38417fbb0bcbbb7e5ab6165d3f6b86c8..f5f996309509167bb8c40380c1510058eddc88c3 100644 (file)
@@ -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 (file)
index 0000000..08e8633
--- /dev/null
@@ -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(), "")
+}
index 58f6eed1e66c3f602487a9c1dcbd0a018596e8e1..89283bb3031d4a2d9c919522567491e5e1c42578 100644 (file)
@@ -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
@@ -234,7 +236,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)
index b772171f930adc43ebf66a93ba57fc65e1650d21..d4002cbccab3d38c84086cb2cb72d025a2606329 100644 (file)
@@ -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. {
index 434edf8ea450967cb4fdf9edeadf6048860b4db1..2eda875bfdee8ab10080f096357891a8c49f2dfb 100644 (file)
@@ -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)
                }
index 30e46ca44f07bdd5d41fa8afda11758e5807024f..255ff5c66a75bfde3bf924c9219189a58d62bd98 100644 (file)
@@ -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
@@ -211,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"`
@@ -234,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},
@@ -320,7 +460,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},
@@ -458,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) {
@@ -591,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 {
index d8c779869b33f89be3d6e5964ce06763a7aba930..3917084dc3324ad5c57e206792cd5704bd12816b 100644 (file)
@@ -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 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
 //
 // 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
@@ -688,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
@@ -806,9 +817,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
index 326bdc9540ef9b71466bf06723b3bcb89963835e..555eff93c0ec38576b7f9d4d1e8772b6aec7ef60 100644 (file)
@@ -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 {
index d6b2992e9be1c3827027a6baa7172f9a10c86014..87f0e57c6cdb5cc810220700b287145d95f858e4 100644 (file)
@@ -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,17 +222,23 @@ 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
 }
 
-// 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.
index 3516ac3b83d9712eac40def7c1a5e493454fa2d7..84edeb187c259240facd75ae2e62fffc75e29539 100644 (file)
@@ -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)
        }
@@ -87,7 +90,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 +112,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)
                }
        }
index b7ea433014b9dcd43cca532de22890e8ab72041d..d5465c518f81d98b95d8b26370a0c12bbec34bd5 100644 (file)
@@ -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
 }
 
index fefc10c19de8ad0c75b7a6f436d04c8cb03e41ee..c312914b44a48bf076934031318ea252f3cc7a9c 100644 (file)
                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
index fa258d3dc671a4d0f8a643fc34fdc08ad78f45c0..9706b8b6b31d6298ee2f18c3639806925911df24 100644 (file)
@@ -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):])
index 8a8c4be2174af0dc7946cb3dd14e99b56a9de522..f9a428edd42b4552694d77ecd024f89b83fc321e 100644 (file)
@@ -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"},
@@ -280,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": {
@@ -364,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",
        },
index aa0d01afdf382680b718014c9298396a2a0c116f..19b9c73568605f3e6e75707996b2450c3c196c6f 100644 (file)
@@ -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, 0)
-       if err != nil {
-               return
-       }
 
        var elfreader io.ReaderAt
        switch string(magic[:]) {
@@ -168,7 +162,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
                }
index eb29df77ab757bdfbbd84373de84a2e616f99d1a..341358287a1ffda5aa474a2a43837e8e542cc35f 100644 (file)
@@ -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()
                }
        }
@@ -162,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))
        }
 }
 
@@ -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
index b2848c3023696af3ccb8b4b3dd6ff09aa6369f32..2c6e676225fb14aa9b38f9757b37a1f32c694246 100644 (file)
@@ -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:
index e56720b0d525435215a4dcd9e66f915d5d024d49..8de36c713c1453363f7b25aced1ecd35ec1c2682 100644 (file)
@@ -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
@@ -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 (file)
index 0000000..9e2e705
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Input for TestIssue15517
+
+package p
+
+const C = 0
+
+var V int
+
+func F() {}
index 33751779a3d9b53615a9b521baf7ab9eeca72ce3..7306083b0dd8ace37c4005dba49f42fdd7462f00 100644 (file)
@@ -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
index c7564bcf85d355772a9ec514eb214cf86a70fe66..6ebf3b5eab0745ae80d4475c1b26db780b3b8b6d 100644 (file)
@@ -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
                        }
                }
index f064f6856f24f7dc1b52d0393bd575e0f11de2be..1ecfb35f60c3ee2357ae928adff25cca1e346190 100644 (file)
@@ -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)
 }
 
index 1536df5bf1bebcdc35ce5a2e1282004b050a3027..992188f0ff47b5eaa10385717049ebbe4f2cc2ce 100644 (file)
@@ -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):
index e301f711590ff4b916fce51d8652aa829c7864c9..5764430b1bf3373cb7e9c698eb4bf804a28800c2 100644 (file)
@@ -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
                        }
index 4fe0c629386776b583188ef35bff3f7d9ea7ebf2..6579aa3b117b65450f4cb4ef9b2cdf6acaed5738 100644 (file)
@@ -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
+}
index ac32ed7ba92f3297dbd8350b56b24d51b79a9c00..0c727c3dd011a97d003104126dc44116d2192ee8 100644 (file)
@@ -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
 }
index 54cc56055e48faac50a62f3637a12dcac65cec01..e939c2a06ac29e15087d6fc5473fa17802747821 100644 (file)
@@ -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)
        }
index 80dca47f3d8b2c78423764eb422e87c244d432bd..480b150e132dcf8aa49727c390224c6e6445c374 100644 (file)
@@ -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)
+       })
+}
index 3715ed5c93805f8dbb8222be2e5142154a3872a5..2e14bd1231f7997f6839892b0a43acbbb9a346e4 100644 (file)
@@ -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
 )
 
index 51a8b2cc5ae645fa8428308d217c9ff4dbf04369..de3254df589f0e31844b147324e418d900a97ebd 100644 (file)
@@ -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 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 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)
 }
index 02d985cec90b0f9ccdf40179a9c5540a1f1f2d93..5426cae90963308313cc186026e9187dcd0b6b78 100644 (file)
@@ -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
index 7e473d4e1de7b2609cb645a05060f02e1803c205..62affc0b50baf45f0ef291a8248cd956fab3914c 100644 (file)
@@ -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
 
index 2eae5e75f9e411e56b4fd44cc62bd333490512f4..7b2bc79cebe4a4b044e184adbadf1cdefeb18024 100644 (file)
@@ -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
 
index d599258976b81d014b3e7fee43520223c770aab6..6929acfa7283f5ec6cc676a9bac7c649e43c7d7a 100644 (file)
@@ -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
 
index 9e684e3034388ebc002f970a24dadf2adaa34175..f134f6b04a185f2f8a8844e652da9ec56f4e5e3f 100644 (file)
@@ -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")
+       }
+}
index 412dfb3b921ba43e2b30e0adfb047cbce577e035..bf16de8fe2357d4d890fa0710a9974c198591048 100644 (file)
@@ -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)
        }
 
index c36ec2afbb0915ea28665cffc5d6c5b42f135369..80398b39973918a43c8a4002a8b9b444fd13e786 100644 (file)
@@ -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)
@@ -480,11 +470,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 {
index e892574b0b5f2e485bc57ea9b9b77bbb562654fb..877e8392e279a00ce0a6550fceed3d13e8194e99 100644 (file)
@@ -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)
        }
index c23c12b151e132c397de655d4117133c61098bb9..ed05cac9e722d5fcff7663ffe55d188fe83c4283 100644 (file)
@@ -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 {
index 787ea341307a1122ee1178d6013f50200f822759..2dce36955ed2603e872bde2003981043303110d1 100644 (file)
@@ -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)
+       }
+}
index 82c903eadbb8b67c02a161d2783a3b583dc8982d..1a1412a00cf57e26ef31996e8e285bf094107bf4 100755 (executable)
@@ -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
index a64777ee917d316985c1b93f37068b9932223b51..bf25b95ca5097d5d52981f7c6b059f00d22d6c37 100644 (file)
@@ -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
index 60162045ede4b077275631489a0eaa0ffe1434d9..243f83cc0f0223fd7e66ecb159a0f9f76f1f4ffd 100755 (executable)
@@ -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
 }
index 7d2f69a7511572ce5a2a0db2053ce7688401fee1..75862b4951fffe64b5900f16a2e2dd31d4891446 100644 (file)
@@ -5,6 +5,7 @@
 package big
 
 import (
+       "fmt"
        "math/rand"
        "testing"
 )
@@ -118,28 +119,22 @@ 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 = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5}
+
+func BenchmarkAddVV(b *testing.B) {
+       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)
+                       }
+               })
        }
 }
 
-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 +231,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 _, n := range benchSizes {
+               x := rndV(n)
+               y := rndW()
+               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)
+                       }
+               })
        }
 }
 
-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 +369,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 _, n := range benchSizes {
+               x := rndV(n)
+               y := rndW()
+               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)
+                       }
+               })
        }
 }
 
-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 +399,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) }
index 563ccb30523adab0c1f4982cc40bc1e67ea2944b..ebb29856549b8ef47a9eb228fa71adfa0f7e7e83 100644 (file)
@@ -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:
index e216bd288ccd2c4432d20518962c6b5a51c9a850..44547842c1ced2f86a225e17f59a35d5c4bd6f47 100644 (file)
@@ -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
                        }
                }
index 028e5a858eb98c4e7054abb709bdb376a1de9a3b..79901d1880477fe6f402f9f95240e1e250d38a7e 100644 (file)
@@ -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
index d693bfb52f243c5216ffbb1e384037675869a042..add039ed4bdade7991d53b1576633a2d6fdc5b4d 100644 (file)
@@ -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
index 80960939d62ecb868fa639f427162ae0df5f5ee2..f82756d55185e2eb4a0cda34dafe98ed192bd748 100644 (file)
@@ -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)
                }
        }
index ba00c97eceea4b6f302a08ce1bd6fb70c8a777cf..9670c660a4a0b72d7c5f544b9ce4783efcf82d54 100644 (file)
@@ -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)
+       }
+}
index c3ba186e7c6b4839a86f54a488989b7d12613b1d..14ff973405186392163ed42dd5db5b1d6e47fec7 100644 (file)
@@ -21,7 +21,7 @@ func initMimePlan9() {
 }
 
 var typeFiles = []string{
-       "/sys/lib/mimetypes",
+       "/sys/lib/mimetype",
 }
 
 func initMimeForTests() map[string]string {
index 52d1dfd3460e6c71966b06df67de64169ee14e5c..51259722aec8e6ce54d0d8e2ed46457afa02b3e4 100644 (file)
@@ -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 "<nil>" }
 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
 }
index 59c40c8d8a7f0cdd4caa8f43508f30b774311dbe..5a1eed843751a45ab72de2365337132f3729f4ba 100644 (file)
@@ -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) {
index 5dc7b1a62d466312a9249eca9ad748a6ee07e852..e861c7aa1f90d8a1372a08d858d778d16c36fff3 100644 (file)
@@ -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)
        }
 }
index 8accbae7bb8c47e0c4fbf3b68f2f2fafe9426e5c..16cf69ee169eaf0435b9e0f0ae95a07a0126b160 100644 (file)
@@ -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))
index 256ef3806147c426c18a4e4cf3756bd293fff221..55edb433953ae8f50e6dda90bda52ddd798baf11 100644 (file)
@@ -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) {
@@ -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}
        }
index ead1e68d46f43e76aa21cbb1c9d9cd87d4481a9a..53656770112a3a9e9c552811d62ddd4545b32192 100644 (file)
@@ -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 }()
@@ -148,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)
        }
@@ -163,7 +163,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()
@@ -326,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)
                }
@@ -446,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)
        }
@@ -501,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)
        }
@@ -591,68 +583,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 +673,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)
@@ -731,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)
                }
index c1ef5a32d3dcd6d3f465de74e41376bc4a651c7c..09bbd488660673284de1408fa9feb1f2bf6314f6 100644 (file)
@@ -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)
        }
 }
index 9f496d7d2db5e8c41a3fcbd7bd237afe3e81b8aa..d6de5a3e68f048c3e6d1546e351852f49dea9aeb 100644 (file)
@@ -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)
+}
index 329d6152b2d9894a2e392c16b14c27bc6d4bb80e..7533232dc9b5eb27c3b74b584f2b4efcf1779220 100644 (file)
@@ -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
@@ -154,9 +157,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)
        }
index 7ef10702ed8c08112fc8382bd1958ca91f9e9176..0f80bc79ac270eb0cddadefe1f570fe526c4dacc 100644 (file)
@@ -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
        }
index 49e79d6a950c04fae759d1e6c799c60b4ca15258..b0b6769eb3cf74ab97e31bcaed07ea36a18f886b 100644 (file)
@@ -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)
        }
index 892775a024f45667bd96f4b6206a3a6df80686a8..2939c09a43097f94503ba2a5204e195eb5e82d53 100644 (file)
@@ -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)
                }
@@ -60,7 +58,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 {
index f8ab675a3de04794384b97cefe9beac77dd2523d..993c247eef536adcc3350ca208ce6613d7c4d191 100644 (file)
@@ -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 {
@@ -442,7 +451,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()
@@ -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()
        }
 }
 
index a9b30b1bf5c1347a25c5deb87fb99aa0a217c2fc..a9b1948005cb66c1e7a233268603756ee9b6ca5b 100644 (file)
@@ -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"},
@@ -1168,3 +1206,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")
+}
index 9c3949fc3970f8125da57a391b1fbc0bbe245026..e12ea0c8c45b409f2559cd066c3011a35c98b1da 100644 (file)
@@ -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
@@ -229,11 +236,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 +1178,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)
                        }
@@ -1200,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()
index 3ebc51b19e62e9e2cf2e6d1abc98171dc9c794ac..9c5ba0809ad0ab200193b1dafd83e6f8eb695432 100644 (file)
@@ -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
+}
index 7cfe72a5dc84759e85960ba50d73e4f5207b5565..9cedcaa73daab23eaedf5bbb5384329d90a7fd10 100644 (file)
@@ -20,15 +20,18 @@ import (
        "bufio"
        "bytes"
        "compress/gzip"
+       "context"
        "crypto/tls"
        "encoding/binary"
        "errors"
        "fmt"
        "golang.org/x/net/http2/hpack"
+       "golang.org/x/net/lex/httplex"
        "io"
        "io/ioutil"
        "log"
        "net"
+       "net/http/httptrace"
        "net/textproto"
        "net/url"
        "os"
@@ -47,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
@@ -247,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{
@@ -299,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 }
@@ -1086,7 +1101,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 +1474,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 +1543,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 {
@@ -1852,7 +1877,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, ":")
@@ -1862,7 +1887,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
                        }
                } else {
                        sawRegular = true
-                       if !http2validHeaderFieldName(hf.Name) {
+                       if !http2validWireHeaderFieldName(hf.Name) {
                                invalid = http2headerFieldNameError(hf.Name)
                        }
                }
@@ -1962,7 +1987,88 @@ func http2summarizeFrame(f http2Frame) string {
        return buf.String()
 }
 
-func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel }
+func http2transportExpectContinueTimeout(t1 *Transport) time.Duration {
+       return t1.ExpectContinueTimeout
+}
+
+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() }
+
+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 && ci.Reused
+       if ci.WasIdle && !cc.lastActive.IsZero() {
+               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 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})
+       }
+}
+
+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"
 
@@ -2320,58 +2426,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') {
-                       return false
-               }
-               if !http2isTokenTable[byte(r)] {
+               if !httplex.IsTokenRune(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
                }
        }
@@ -2476,7 +2547,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:
@@ -2502,86 +2573,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
 }
@@ -2938,10 +2929,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(),
@@ -2960,6 +2955,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)
@@ -3032,6 +3028,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
@@ -3095,10 +3092,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
@@ -3112,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
@@ -3475,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()
 }
 
@@ -3762,6 +3776,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
@@ -3941,10 +3956,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
@@ -3989,6 +4007,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)
@@ -4012,6 +4032,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)
                }
        }
@@ -4150,6 +4174,7 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
                Body:       body,
                Trailer:    trailer,
        }
+       req = http2requestWithContext(req, st.ctx)
        if bodyOpen {
 
                buf := make([]byte, http2initialWindowSize)
@@ -4192,6 +4217,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:
@@ -4340,7 +4366,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
@@ -4415,9 +4441,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) {
@@ -4707,6 +4733,72 @@ 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)
+       }
+}
+
+// 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.
@@ -4833,6 +4925,8 @@ type http2ClientConn struct {
        bw           *bufio.Writer
        br           *bufio.Reader
        fr           *http2Framer
+       lastActive   time.Time
+
        // Settings from peer:
        maxFrameSize         uint32
        maxConcurrentStreams uint32
@@ -4850,10 +4944,12 @@ 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
        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
@@ -4875,28 +4971,34 @@ 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:
        }
 }
 
-// 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
        }
@@ -4964,6 +5066,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
@@ -4980,7 +5083,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()
        }
 }
@@ -5057,6 +5160,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())
@@ -5254,6 +5364,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
@@ -5265,67 +5399,62 @@ 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()
        if cc.closed || !cc.canTakeNewRequestLocked() {
                cc.mu.Unlock()
                return nil, http2errClientConnUnusable
        }
 
-       cs := cc.newStream()
-       cs.req = 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)
+       cs.requestedGzip = requestedGzip
+       bodyWriter := cc.t.getBodyWriterState(cs, body)
+       cs.on100 = bodyWriter.on100
+
        cc.wmu.Lock()
        endStream := !hasBody && !hasTrailers
        werr := cc.writeHeaders(cs.ID, endStream, hdrs)
        cc.wmu.Unlock()
+       http2traceWroteHeaders(cs.trace)
        cc.mu.Unlock()
 
        if werr != nil {
                if hasBody {
                        req.Body.Close()
+                       bodyWriter.cancel()
                }
                cc.forgetStreamID(cs.ID)
 
+               http2traceWroteRequest(cs.trace, werr)
                return nil, werr
        }
 
        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 {
                        timer := time.NewTimer(d)
                        defer timer.Stop()
@@ -5334,8 +5463,8 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
        }
 
        readLoopResCh := cs.resc
-       requestCanceledCh := http2requestCancel(req)
        bodyWritten := false
+       ctx := http2reqContext(req)
 
        for {
                select {
@@ -5343,6 +5472,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 {
@@ -5357,21 +5487,32 @@ 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
-               case <-requestCanceledCh:
+               case <-ctx.Done():
+                       cc.forgetStreamID(cs.ID)
+                       if !hasBody || bodyWritten {
+                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+                       } else {
+                               bodyWriter.cancel()
+                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+                       }
+                       return nil, ctx.Err()
+               case <-req.Cancel:
                        cc.forgetStreamID(cs.ID)
                        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:
+               case err := <-bodyWriter.resc:
                        if err != nil {
                                return nil, err
                        }
@@ -5429,6 +5570,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 {
@@ -5516,7 +5658,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 {
@@ -5543,7 +5685,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
@@ -5551,6 +5693,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" {
@@ -5568,7 +5721,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":
@@ -5595,7 +5748,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
@@ -5671,8 +5824,10 @@ 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)
+               cc.cond.Broadcast()
        }
        return cs
 }
@@ -5794,6 +5949,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 {
@@ -5839,7 +5998,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
        }
@@ -5892,13 +6054,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
 }
@@ -6248,6 +6411,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
@@ -6470,13 +6706,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
                        }
index a121628632f99aadee7e62147cfed6b8e2e87819..4d088a5bb1c8121787dbaa899e107bc8c2bc6365 100644 (file)
@@ -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)
+}
index b1f49541d576e556dee47786b33627da77097552..0ad26a3d418005c4f8ed92cba932c5fc9cbfef9e 100644 (file)
@@ -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
 }
index 19a37b6c54d2d656141c465228f3296c1c16808e..d4e7137913e4924f0b1f4db5ad4e666961c5e98d 100644 (file)
@@ -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 {
index 5d2c548b3cc310fbbbad0daea0ffaeac7834be6a..6f187a7b694a84d47823a32d14c19a34faaf405b 100644 (file)
@@ -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
index ed6ddbb40dbd173929fdd32a8e7aff117460a1c3..c7eaed83d478518ced0953b20e3702b52d2818d4 100644 (file)
@@ -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)
                }
index 44d15ff6be7f086fdf98fe35fad4f51bc3716428..49c120afde12fc5f48054a2e7e94fe5887f4e92d 100644 (file)
@@ -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}
 }
index e9c0658271f06cdf68c754bb7c4e19b2c23f4d40..fe7cdb888f5ced12d4b5aa3831b0dd2d29325090 100644 (file)
@@ -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)
index a136dc99a65fc82271839e8f1245539a50d09601..9abe1ab6d9d674da8be9d6636f5e75a548491e74 100644 (file)
@@ -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)
index 1bde114909c38eaff04cead872059f9b575d19a3..e8780dea943c975354647156e616642daae03eb6 100644 (file)
@@ -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
@@ -885,68 +890,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
+       }
+
+       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()
        }
-       l.n -= int64(n)
-       if l.n < 0 {
-               l.n = 0
+       if res, ok := l.w.(requestTooLarger); ok {
+               res.requestTooLarge()
        }
-       return
+       l.err = errors.New("http: request body too large")
+       return n, l.err
 }
 
 func (l *maxBytesReader) Close() error {
index 82c7af3cda8dbedeff0a0bc4f79a9115dba1b936..a4c88c02915ccdf3ada229bda2b6524b1f1623c0 100644 (file)
@@ -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 {
index 0164a09c6a0d2a76bff4a2e834bd7e53dda274ad..979651c08a28b6d7afc4363c95348dee71703a41 100644 (file)
@@ -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
index 661f355d0dd7090736b31ec188458f93c73b86d5..c32ff299029a49ed74be0f48dbb6a7bec5beac6c 100644 (file)
@@ -11,6 +11,7 @@ import (
        "bytes"
        "context"
        "crypto/tls"
+       "encoding/json"
        "errors"
        "fmt"
        "internal/testenv"
@@ -714,6 +715,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 +775,54 @@ 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))
+}
+
+// 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) }
 
@@ -3990,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():
@@ -4002,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)
        }
@@ -4056,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 {
@@ -4066,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)
        }
@@ -4268,7 +4356,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
                }
index 23fb84fcdabf410ef3b1af208108acb052654e9b..1a8c0fc6cc27ba3d360098e604937d72990ecd4a 100644 (file)
@@ -27,6 +27,8 @@ import (
        "sync"
        "sync/atomic"
        "time"
+
+       "golang.org/x/net/lex/httplex"
 )
 
 // Errors used by the HTTP server.
@@ -91,10 +93,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.
@@ -769,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")
                        }
                }
@@ -994,7 +1010,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"
@@ -1027,6 +1043,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
 
@@ -2065,7 +2084,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
index f3dacab6a92043bf0ffa12515a384e7ed5cc5479..98645b7d746637e384df443702cd3d90be8d9800 100644 (file)
@@ -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",
 }
 
index 501e4be08cba59360796e46a4d782cf09dc7699b..b27ace638a191f39587c07cb3d4975acd61342c5 100644 (file)
@@ -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 {
index 7fdd94e05bc768e7dd6966d68e70e4293f24a01a..43b20f2da2f86ad7c0633a40e1059116828a0b52 100644 (file)
@@ -26,6 +26,8 @@ import (
        "strings"
        "sync"
        "time"
+
+       "golang.org/x/net/lex/httplex"
 )
 
 // DefaultTransport is the default implementation of Transport and is
@@ -35,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,
@@ -85,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.
        //
@@ -195,22 +197,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.
-               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)
+       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
        }
        t2, err := http2configureTransport(t)
@@ -325,11 +317,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)
                                }
                        }
@@ -387,47 +379,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 +562,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")
 )
 
@@ -784,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)
@@ -852,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
@@ -881,12 +874,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 +997,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 +1152,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 +1165,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 +1208,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
 }
@@ -1221,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
 }
 
@@ -1247,6 +1262,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 +1348,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 +1363,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 +1380,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 +1567,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 +1694,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 +1749,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 +1774,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 +1784,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 +1811,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() {
@@ -1952,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,
        }
 }
 
@@ -1983,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,
        }
 }
 
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
new file mode 100644 (file)
index 0000000..a157d90
--- /dev/null
@@ -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
+}
index bde052524cb8da01ecceed64ba0214d3a965ad7b..1c1a1d0397234b25164eeab193211bdd43f4fac0 100644 (file)
@@ -2983,6 +2983,21 @@ func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) {
 func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
        testTransportAutoHTTP(t, &Transport{
                ExpectContinueTimeout: 1 * time.Second,
+       }, true)
+}
+
+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)
 }
 
@@ -3193,26 +3208,33 @@ 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) {
+       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 ts.Close()
-       tr := &Transport{
-               ExpectContinueTimeout: 1 * time.Second,
-       }
-       defer tr.CloseIdleConnections()
-       c := &Client{Transport: tr}
+       defer cst.close()
+
+       cst.tr.ExpectContinueTimeout = 1 * time.Second
 
        var mu sync.Mutex
        var buf bytes.Buffer
@@ -3223,7 +3245,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 +3260,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) },
@@ -3254,7 +3277,10 @@ func testTransportEventTrace(t *testing.T, 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
@@ -3263,14 +3289,16 @@ 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)
        }
+       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)
        }
@@ -3289,16 +3317,71 @@ func testTransportEventTrace(t *testing.T, 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:<nil> Coalesced:false}")
-       wantSub("connected to tcp " + ts.Listener.Addr().String() + " = <nil>")
+       wantSub("Connecting to tcp " + addrStr)
+       wantSub("connected to tcp " + addrStr + " = <nil>")
        wantSub("Reused:false WasIdle:false IdleTime:0s")
        wantSub("first response byte")
-       wantSub("PutIdleConn = <nil>")
-       wantSub("WroteRequest: {Err:<nil>}")
+       if !h2 {
+               wantSub("PutIdleConn = <nil>")
+       }
        wantSub("Wait100Continue")
        wantSub("Got100Continue")
+       wantSub("WroteRequest: {Err:<nil>}")
+       if strings.Contains(got, " to udp ") {
+               t.Errorf("should not see UDP (DNS) connections")
+       }
+       if t.Failed() {
+               t.Errorf("Output:\n%s", got)
+       }
+}
+
+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)
        }
index 98d19f2d33d42f9789d289b2a95b5fb0e82e5c75..d791cb30167943cc9355cb08635ad9a99efd58fe 100644 (file)
@@ -7,74 +7,54 @@
 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)
+       msgs, err := interfaceMessages(ifindex)
        if err != nil {
-               return nil, os.NewSyscallError("routerib", err)
+               return nil, err
        }
-       msgs, err := syscall.ParseRoutingMessage(tab)
-       if err != nil {
-               return nil, os.NewSyscallError("parseroutingmessage", err)
+       n := len(msgs)
+       if ifindex != 0 {
+               n = 1
        }
-       return parseInterfaceTable(ifindex, msgs)
-}
-
-func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
-       var ift []Interface
-loop:
+       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,75 +82,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
-                       ifa.Zone = ifi.Name
-               }
-       }
-       if ifa.IP == nil || ifa.Mask == nil {
-               return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
-       }
-       return ifa, nil
-}
index ed1af554ad42947798985749b055db89c883cabe..69b0fbcab3de30f6928562d9d4496e87b457dbdd 100644 (file)
@@ -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
similarity index 54%
rename from src/net/interface_netbsd.go
rename to src/net/interface_bsdvar.go
index cb7a34ab16600471c63fef5228ef5fa84cda789b..a809b5f5ce49e6cf31e07cea02ab3fe34e6b7736 100644 (file)
@@ -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) {
index 72fb9443c07d496ef1a76372cb4df60775f2b6dc..bb4fd73a987670bca842c0783d84c03324c3e41d 100644 (file)
@@ -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_dragonfly.go b/src/net/interface_dragonfly.go
deleted file mode 100644 (file)
index cb7a34a..0000000
+++ /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
-}
index bddee8bacb75f2a50642f360c7808f8db620c4ef..45badd64954a17d087eab9a9540b94acd2d938e4 100644 (file)
@@ -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
-       }
-}
index b8f57fd7db39f0046607c0287f726ee9dcbea5b9..5e391b28b0f8c4b2f83b4a9353d8249655dbb12f 100644 (file)
@@ -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_openbsd.go b/src/net/interface_openbsd.go
deleted file mode 100644 (file)
index cb7a34a..0000000
+++ /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
-}
index c3e1ee231ffce9642f254c88d0c5b028d103797d..4c695b902a226cea819f8c4687829bf93a471075 100644 (file)
@@ -5,7 +5,7 @@
 package net
 
 import (
-       "internal/testenv"
+       "fmt"
        "reflect"
        "runtime"
        "testing"
@@ -48,24 +48,11 @@ 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)
-       }
        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,56 +68,7 @@ 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)
        }
 }
 
@@ -139,142 +77,217 @@ func TestInterfaceAddrs(t *testing.T) {
        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) {
+       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) {
+       ift, err := Interfaces()
+       if err != nil {
+               t.Fatal(err)
+       }
+       ifStats := interfaceStats(ift)
+       ifat, err := InterfaceAddrs()
+       if err != nil {
+               t.Fatal(err)
+       }
+       uniStats, err := validateInterfaceUnicastAddrs(ifat)
        if err != nil {
                t.Fatal(err)
        }
-       return testMulticastAddrs(t, ifmat)
+       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
+}
+
+type routeStats struct {
+       ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes
 }
 
-func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
+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)
                                }
-                               if ifa.IP.IsLinkLocalUnicast() && ifa.Zone == "" {
-                                       t.Errorf("no IPv6 zone identifier found: %#v", ifa)
-                                       continue
-                               }
-                               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 %q", 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) {
index 2ebf0897360be9e678df12100f84054d27e0e82f..36510ebf080fbf54cbfe04f7995a6d1ead9dcad6 100644 (file)
@@ -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 {
index 69de095e667d8cf162d864561c8d92232f5e5608..8b976e585f36aab51876c2a1b36681c074532b72 100644 (file)
@@ -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)
                                }
                        }
index e8b0fd990bf896f68e4265ce5a33c265603a7371..d0c82630b57830efbb3106eb737470d04052a743 100644 (file)
@@ -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
@@ -256,7 +255,7 @@ func (ip IP) Mask(mask IPMask) IP {
 // It returns one of 4 forms:
 //   - "<nil>", 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
@@ -273,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.
@@ -339,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
 }
@@ -484,26 +483,22 @@ 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 {
                return "<nil>"
        }
-       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).
@@ -646,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 {
@@ -664,29 +659,28 @@ 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 {
                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
 }
index 1d67057d6afbbc9896c54afe15373b574da96d62..b6ac26da05b84abfd666af7954274c3a87f76fbc 100644 (file)
@@ -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"},
        },
@@ -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"},
 }
 
index 73147a2d3f7c40d69f6ddda33ff53647cf7ef482..3f7af2a1747c32d3050a184ce6fd319edc197839 100644 (file)
@@ -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
        }
index 6e54fdba76d902a1cf09511ba22eebd842d1c48b..e22d1fbf79b42f1f2d8518b5a3314548770fe0ec 100644 (file)
@@ -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 {
@@ -369,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()
@@ -498,6 +511,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 +523,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 +545,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 +558,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.") {
@@ -589,54 +609,40 @@ func srvString(srvs []*SRV) string {
        return buf.String()
 }
 
-var lookupPortTests = []struct {
-       network string
-       name    string
-       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},
-
-       {"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},
-       {"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},
-       {"tcp6", "", 0, true},
-       {"tcp4", "", 0, true},
-       {"udp", "", 0, true},
-}
-
 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},
+       }
+
        switch runtime.GOOS {
        case "nacl":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -644,11 +650,19 @@ 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 {
-               if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
+       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)
                }
+               if err != nil {
+                       if perr := parseLookupPortError(err); perr != nil {
+                               t.Error(perr)
+                       }
+               }
        }
 }
index 5461fe8a411e8d60e6eb8a71c43382356285fe90..15397e8105a92e84ecebe35489edabf9b9ceaf01 100644 (file)
@@ -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
                }
        }
index 9e6907c09a24cbedbb3cdb5d1e29c57fd53cb64e..766de6a815b9dfac62f21e0e4e99ceaa9d7a4fb3 100644 (file)
@@ -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) {
@@ -228,7 +224,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
        }
index 27e9ca367d4054adaaa39ac6168d583ae6faf6b3..d6812d1ef054dc03e57b9f53fa7689da924c46dd 100644 (file)
@@ -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
        }
index 94392928c2df6083949a4f2d10ba4f85ddf878c1..b2f825daffc93c8f97fc0efaa917d4a0779ed27d 100644 (file)
@@ -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)
+               }
+       }
+}
index 0a118874c25aef7912c82054b1b6f45149bf013e..5f1eb19e1240bdc9907810482a3102ddb18e707e 100644 (file)
@@ -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)
        }
 }
index 86010927b321ef3b42bad87872bd72453d35c878..7991a579fd1b349b1319688bbd0bf00aee4f48d1 100644 (file)
@@ -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}
index 05b41fa964a9ccde6ab7d88eeb3512f91f5f34c4..30e92779370393e4f425a379c18225ef8c971f63 100644 (file)
@@ -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"
@@ -573,12 +577,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
index da6bc2843e52b06249ba3c87e4468655bd5e079c..7560f22c4a1e2a7f258b7d4f2f256a6e02859938 100644 (file)
@@ -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
index 5121b9b2ccca48b97392882d2e475d77535d7a30..10300ce234a75120340a183d89c350f954ed5cc4 100644 (file)
@@ -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:
                        }
index 1151ca7d0f0c26dd7d34ce698ff7e3cd614fb5b9..41f9dfe1c6361453a37d56a0808553722042f7e0 100644 (file)
@@ -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 {
@@ -660,10 +668,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,
@@ -838,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)
@@ -847,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)
        }
@@ -862,7 +866,7 @@ func TestContext(t *testing.T) {
        }
        waitErr := make(chan error, 1)
        go func() {
-               waitErr <- c.WaitContext(ctx)
+               waitErr <- c.Wait()
        }()
        cancel()
        select {
index 82678802a96483d62e65d1ee7ce192ae5de2341d..142f87ed32b3b52e26e518ca8645494304fd5d15 100644 (file)
@@ -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}
index 32e3046cb8740108c88cfea65427748b5c5c57c6..7a302752a8974dc04e16d937d96b65e6b8c02575 100644 (file)
@@ -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
                }
index 1c005220d01bc3439b282d0d81c16df1e2a67852..793d4d98b3a6aef429196c9f4a5186af131944ae 100644 (file)
@@ -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
-}
index 042e5a1389eb7db019d24441b3fef7cef40bed56..96a22d843f8544775555584895848f5f11f7596f 100644 (file)
@@ -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])
        }
index 0fe1b8213dc54bdf2d180af29262ea5992bec2b1..9edb6bc0747d08fbacd3aded37af37fa1f6c1a81 100644 (file)
@@ -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}
                }
        }
@@ -145,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
@@ -419,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
 }
index 137f24a0a95979dabcca244e573e5ceae6c2b1aa..f470fc4315cc2b987fab3518beeb88226bf12cf2 100644 (file)
@@ -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),
@@ -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
+                                       }
+                               }
                        }
                }
        }
index 8f62902a6caaf8a967d2ee02ee0c1dc0cede654f..baa2f07fd2b0f322bb4cc025af6fd8206b85eabb 100644 (file)
@@ -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)
@@ -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())
@@ -1726,7 +1758,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) }},
index c47f5462ab56c874bd921593fd7db12dc4ba46a4..5c10154760cbe756b7548854eb33529cdb4d9ce7 100644 (file)
@@ -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)
index 2f7d48d5bdf06c57112815a0a3fbed1195e65a80..05d7a8f34e9a9f4f721087ff57774d270ea461da 100644 (file)
@@ -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)
+       }
+}
index 9ee547b15db420562d2fd25178d8dbb08bd9e058..73b01a2764de60667979964bb3cc3ad21d677f6d 100644 (file)
@@ -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.
 
similarity index 64%
rename from src/os/user/getgrouplist_darwin.c
rename to src/os/user/getgrouplist_darwin.go
index 6ad561489829ea682e4c9cb63b1f7e5863308050..54a2da3610434c0ec64e2dcf547340b1a675fe85 100644 (file)
@@ -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 <unistd.h>
 #include <sys/types.h>
 #include <stdlib.h>
 
-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)
+}
similarity index 56%
rename from src/os/user/getgrouplist_unix.c
rename to src/os/user/getgrouplist_unix.go
index eb14f9ab8a0ac176ec81434c2d85e46d7f3861f2..14da7c00a2b55de0319b6a790fdf243f6b4b88b9 100644 (file)
@@ -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 <unistd.h>
 #include <sys/types.h>
 #include <grp.h>
 
-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)
+}
index f78baaac1e27f7153c3025c7ddf1dc469cf2cfb9..db952c64bffdb3b76be729aebf71b60a785c2fb4 100644 (file)
@@ -16,8 +16,6 @@ import (
 #include <unistd.h>
 #include <sys/types.h>
 #include <stdlib.h>
-
-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)
                }
index d64bf84fc0a9efc38a746f9cf51105c02900858f..2adb0c7490821e75e6fd4988bdad8c80ef506c7b 100644 (file)
@@ -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
index d8bab7f4da3969265c6de021e9aa93ce0b3f04a1..8dcfa5972e551f59ca092453653571a75045d0dd 100644 (file)
@@ -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)
+               }
+       }
+}
index d4c3e4e588a89d70bbd306fefc3bc741e334ff61..f7cf46daecf524b278e6fd60a0e4d5e4f8bffb4f 100644 (file)
@@ -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) })
@@ -2388,13 +2328,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,17 +2356,8 @@ var unexpi unexpI = new(unexp)
 func TestUnexportedMethods(t *testing.T) {
        typ := TypeOf(unexpi)
 
-       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'")
+       if got := typ.NumMethod(); got != 0 {
+               t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
        }
 }
 
@@ -2918,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) {
@@ -4210,7 +4140,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 +4450,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 +4678,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 +4690,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 {
@@ -5187,7 +5117,7 @@ func useStack(n int) {
 
 type Impl struct{}
 
-func (Impl) f() {}
+func (Impl) F() {}
 
 func TestValueString(t *testing.T) {
        rv := ValueOf(Impl{})
@@ -5221,6 +5151,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) {
@@ -5737,13 +5702,38 @@ 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
+               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)
+               }
+       }
+}
+
+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()
 }
index 00189f3353f19678ce295d41a96c92d6084611be..2cc1530250c084e536ad09ca9d1a69baf4bd9442 100644 (file)
@@ -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))
+}
index 2ceb3d3f661726469a8d65a9ef6456f99a0f48bc..1dff74df62a06fef6d5642c8a2acd8357ff0114b 100644 (file)
@@ -763,16 +763,62 @@ 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
+}
+
+func (t *rtype) exportedMethods() []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()
+       allExported := true
+       for _, m := range allm {
+               name := t.nameOff(m.name)
+               if !name.isExported() {
+                       allExported = false
+                       break
+               }
+       }
+       if allExported {
+               methods = allm
+       } else {
+               methods = make([]method, 0, len(allm))
+               for _, m := range allm {
+                       name := t.nameOff(m.name)
+                       if name.isExported() {
+                               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.exportedMethods())
 }
 
 func (t *rtype) Method(i int) (m Method) {
@@ -780,40 +826,31 @@ 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.exportedMethods()
+       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 == "" {
-                       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 +868,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
                }
        }
@@ -1178,7 +1215,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)
@@ -1985,6 +2022,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))
@@ -2313,10 +2351,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 {")...)
@@ -2758,7 +2792,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.
index e6c2ce5940ac2e3396648b9d141aac63b8817600..efc0b435711f3cfd1f50cc5d6d21090c5b5a7588 100644 (file)
@@ -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
index 3acf46a9961a2dcc4b889c156303ec1bf0f85648..293b775efa5e77bac473df02ea5c3dd4eb08f9a2 100755 (executable)
@@ -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
index 01a66bc574876aefd021e707a494620e853178e8..6e42922a86e594f372f077846435a539c4333322 100644 (file)
@@ -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
 
index d314808f3f28a7c2b3c7001324921ee318404ee9..88d77912e31efc74088c885abdd47d275c3b27a4 100755 (executable)
@@ -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 $*
index cd28e3dca6933c2712a91d01a50d7efa3c93bc4c..6b8968e382d349632a8bbcf1c68a2a244477338e 100644 (file)
@@ -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
index 6cd31f951bda747b75e47b3f84f1016547830bd7..e50c44304441de2ab405ff39c445e2b0232ed365 100644 (file)
@@ -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
@@ -1800,6 +1801,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
index 4fb4a613e044d4fdeecba9b3ea96900a3583e994..9cf7b58a2f7a2ec301f66956a4fe20411c68bf96 100644 (file)
@@ -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
index 08472b6ab76ad9a00c3cca946e1a2245873d40e0..0f354220bbf0b75cb130fef582de1b0cb45c4b79 100644 (file)
@@ -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
index d0f63fb4ff9d74a583f7991554783e64adef9b2a..9bde5a933fcd15da4e1e41031c73c4da01199302 100644 (file)
@@ -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
index 22941a4c6d458ff220587e182fa4b077bbb4e42a..1bc61ff7087bf972366c6589895790e77447eb2f 100644 (file)
 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);
index e84fe6c18b035f9e789cb43b92c561ef5d910d38..4d4d14314c790b11e2aad461d08132b0ed2a7ad7 100644 (file)
 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);
 }
 
index e20d206be6d7996407b9cb84e6118bdff161d270..4111fe11951df885c29052c6e2a4b634b842bd13 100644 (file)
@@ -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)
index 8457fb2de73c71a415f3a97d236c4f1f6debf26e..0f8386b10f54d50e26a569c5acd69f0a8f41e9ff 100644 (file)
@@ -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) {
@@ -601,7 +582,7 @@ func cgoIsGoPointer(p unsafe.Pointer) bool {
                return false
        }
 
-       if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
+       if inHeapOrStack(uintptr(p)) {
                return true
        }
 
index d85d5fe5a8ba15fd1276f28a4fc2b71b98058f21..2d064145a415de3bf071ee10a5c1f0a92d3b74a7 100644 (file)
@@ -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
index 771b303f6ee39aee0025469353f698d497f736c1..0a79661f1ead831c3b3652a07afea9715a9cbb49 100644 (file)
@@ -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)
index bb17919fd0135d7cd18225830a751d63dfb24dde..b079a07d518456a962634802aa019693c31b9424 100644 (file)
@@ -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)
@@ -723,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
index cdb36cd65145bd279721cf771f30d47fcce8222d..ccefbcd8d62df23e3b08b051fd013d846cefcf9d 100644 (file)
@@ -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.
@@ -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
@@ -849,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.
index 8bf0c65e2983298b92973fa3e0b752f9f18363a0..2124cb9d499d50435b19b53e14700b1d52a92cdf 100644 (file)
@@ -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++ {
index 6dce6d75011ec9d5ca8fa40bc158051f0563c025..1a744e4a51e697d32a29289fb4b0e9ec63d54ffa 100644 (file)
@@ -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{}) {}
index c497ccee67e724c240d6d2fc33adad80c5ad0b9f..c50bd028810f0b947c3c29d792bd565aed3654a4 100644 (file)
@@ -1389,7 +1389,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 {
@@ -1705,7 +1705,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()
index af3205ab2332bfcd28f8fab1be9097d54e367bbd..00b96fd00beed2d03157cd7f3965196d23b149fe 100644 (file)
@@ -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:
@@ -231,7 +233,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)
@@ -601,7 +603,13 @@ func gcFlushBgCredit(scanWork int64) {
                        gp.gcAssistBytes = 0
                        xgp := gp
                        gp = gp.schedlink.ptr()
-                       ready(xgp, 0)
+                       // 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
@@ -636,8 +644,18 @@ 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
-func scanstack(gp *g) {
+//go:systemstack
+func scanstack(gp *g, gcw *gcWork) {
        if gp.gcscanvalid {
                return
        }
@@ -726,7 +744,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)
@@ -754,9 +771,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
@@ -1096,7 +1110,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
index 1f732c2111c975ddd6433e9af1c9e7024d192b43..4093288a7cb382238bc806c03898f9337ebd324e 100644 (file)
@@ -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.
 
@@ -1221,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 {
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
deleted file mode 100644 (file)
index 0dafe02..0000000
+++ /dev/null
@@ -1,281 +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 runtime
-
-import (
-       "runtime/internal/sys"
-       "unsafe"
-)
-
-// From FreeBSD's <sys/sysctl.h>
-const (
-       _CTL_HW  = 6
-       _HW_NCPU = 3
-)
-
-var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
-
-func getncpu() int32 {
-       mib := [2]uint32{_CTL_HW, _HW_NCPU}
-       out := uint32(0)
-       nout := unsafe.Sizeof(out)
-       ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
-       if ret >= 0 {
-               return int32(out)
-       }
-       return 1
-}
-
-// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
-// thus the code is largely similar. See Linux implementation
-// and lock_futex.go for comments.
-
-//go:nosplit
-func futexsleep(addr *uint32, val uint32, ns int64) {
-       systemstack(func() {
-               futexsleep1(addr, val, ns)
-       })
-}
-
-func futexsleep1(addr *uint32, val uint32, ns int64) {
-       var tsp *timespec
-       if ns >= 0 {
-               var ts timespec
-               ts.tv_nsec = 0
-               ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
-               tsp = &ts
-       }
-       ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
-       if ret >= 0 || ret == -_EINTR {
-               return
-       }
-       print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
-       *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
-}
-
-//go:nosplit
-func futexwakeup(addr *uint32, cnt uint32) {
-       ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
-       if ret >= 0 {
-               return
-       }
-
-       systemstack(func() {
-               print("umtx_wake_addr=", addr, " ret=", ret, "\n")
-       })
-}
-
-func thr_start()
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
-       if false {
-               print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
-       }
-
-       // NOTE(rsc): This code is confused. stackbase is the top of the stack
-       // and is equal to stk. However, it's working, so I'm not changing it.
-       param := thrparam{
-               start_func: funcPC(thr_start),
-               arg:        unsafe.Pointer(mp),
-               stack_base: mp.g0.stack.hi,
-               stack_size: uintptr(stk) - mp.g0.stack.hi,
-               child_tid:  unsafe.Pointer(&mp.procid),
-               parent_tid: nil,
-               tls_base:   unsafe.Pointer(&mp.tls[0]),
-               tls_size:   unsafe.Sizeof(mp.tls),
-       }
-
-       var oset sigset
-       sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
-       thr_new(&param, int32(unsafe.Sizeof(param)))
-       sigprocmask(_SIG_SETMASK, &oset, nil)
-}
-
-func osinit() {
-       ncpu = getncpu()
-}
-
-var urandom_dev = []byte("/dev/urandom\x00")
-
-//go:nosplit
-func getRandomData(r []byte) {
-       fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
-       n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-       closefd(fd)
-       extendRandom(r, int(n))
-}
-
-func goenvs() {
-       goenvs_unix()
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
-       mp.gsignal = malg(32 * 1024)
-       mp.gsignal.m = mp
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-       sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-       sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
-       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
-       _g_ := getg()
-
-       // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
-       // Fix it up. (Only matters on big-endian, but be clean anyway.)
-       if sys.PtrSize == 4 {
-               _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
-       }
-
-       // Initialize signal handling.
-       var st stackt
-       sigaltstack(nil, &st)
-       if st.ss_flags&_SS_DISABLE != 0 {
-               signalstack(&_g_.m.gsignal.stack)
-               _g_.m.newSigstack = true
-       } else {
-               // Use existing signal stack.
-               stsp := uintptr(unsafe.Pointer(st.ss_sp))
-               _g_.m.gsignal.stack.lo = stsp
-               _g_.m.gsignal.stack.hi = stsp + st.ss_size
-               _g_.m.gsignal.stackguard0 = stsp + _StackGuard
-               _g_.m.gsignal.stackguard1 = stsp + _StackGuard
-               _g_.m.gsignal.stackAlloc = st.ss_size
-               _g_.m.newSigstack = false
-       }
-
-       // restore signal mask from m.sigmask and unblock essential signals
-       nmask := _g_.m.sigmask
-       for i := range sigtable {
-               if sigtable[i].flags&_SigUnblock != 0 {
-                       nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
-               }
-       }
-       sigprocmask(_SIG_SETMASK, &nmask, nil)
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-func unminit() {
-       if getg().m.newSigstack {
-               signalstack(nil)
-       }
-}
-
-func memlimit() uintptr {
-       /*
-               TODO: Convert to Go when something actually uses the result.
-               Rlimit rl;
-               extern byte runtime·text[], runtime·end[];
-               uintptr used;
-
-               if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
-                       return 0;
-               if(rl.rlim_cur >= 0x7fffffff)
-                       return 0;
-
-               // Estimate our VM footprint excluding the heap.
-               // Not an exact science: use size of binary plus
-               // some room for thread stacks.
-               used = runtime·end - runtime·text + (64<<20);
-               if(used >= rl.rlim_cur)
-                       return 0;
-
-               // If there's not at least 16 MB left, we're probably
-               // not going to be able to do much. Treat as no limit.
-               rl.rlim_cur -= used;
-               if(rl.rlim_cur < (16<<20))
-                       return 0;
-
-               return rl.rlim_cur - used;
-       */
-
-       return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
-       sa_handler uintptr
-       sa_flags   int32
-       sa_mask    sigset
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
-       var sa sigactiont
-       sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
-       if restart {
-               sa.sa_flags |= _SA_RESTART
-       }
-       sa.sa_mask = sigset_all
-       if fn == funcPC(sighandler) {
-               fn = funcPC(sigtramp)
-       }
-       sa.sa_handler = fn
-       sigaction(i, &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-       throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func getsig(i int32) uintptr {
-       var sa sigactiont
-       sigaction(i, nil, &sa)
-       if sa.sa_handler == funcPC(sigtramp) {
-               return funcPC(sighandler)
-       }
-       return sa.sa_handler
-}
-
-//go:nosplit
-func signalstack(s *stack) {
-       var st stackt
-       if s == nil {
-               st.ss_flags = _SS_DISABLE
-       } else {
-               st.ss_sp = s.lo
-               st.ss_size = s.hi - s.lo
-               st.ss_flags = 0
-       }
-       sigaltstack(&st, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
-       var mask sigset
-       copy(mask.__bits[:], m[:])
-       sigprocmask(_SIG_SETMASK, &mask, nil)
-}
-
-func unblocksig(sig int32) {
-       var mask sigset
-       mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
-       sigprocmask(_SIG_UNBLOCK, &mask, nil)
-}
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
deleted file mode 100644 (file)
index feea496..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import "unsafe"
-
-type sigset struct{}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
-       mp.gsignal = malg(32 * 1024)
-       mp.gsignal.m = mp
-}
-
-func sigtramp()
-
-//go:nosplit
-func msigsave(mp *m) {
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-}
-
-//go:nosplit
-func sigblock() {
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
-       _g_ := getg()
-
-       // Initialize signal handling
-       ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
-       if ret < 0 {
-               print("runtime: nacl_exception_stack: error ", -ret, "\n")
-       }
-
-       ret = nacl_exception_handler(funcPC(sigtramp), nil)
-       if ret < 0 {
-               print("runtime: nacl_exception_handler: error ", -ret, "\n")
-       }
-}
-
-// Called from dropm to undo the effect of an minit.
-func unminit() {
-}
-
-func osinit() {
-       ncpu = 1
-       getg().m.procid = 2
-       //nacl_exception_handler(funcPC(sigtramp), nil);
-}
-
-func signame(sig uint32) string {
-       if sig >= uint32(len(sigtable)) {
-               return ""
-       }
-       return sigtable[sig].name
-}
-
-func crash() {
-       *(*int32)(nil) = 0
-}
-
-//go:noescape
-func getRandomData([]byte)
-
-func goenvs() {
-       goenvs_unix()
-}
-
-func initsig(preinit bool) {
-}
-
-//go:nosplit
-func usleep(us uint32) {
-       var ts timespec
-
-       ts.tv_sec = int64(us / 1e6)
-       ts.tv_nsec = int32(us%1e6) * 1e3
-       nacl_nanosleep(&ts, nil)
-}
-
-func mstart_nacl()
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
-       mp.tls[0] = uintptr(unsafe.Pointer(mp.g0))
-       mp.tls[1] = uintptr(unsafe.Pointer(mp))
-       ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&mp.tls[2]), nil)
-       if ret < 0 {
-               print("nacl_thread_create: error ", -ret, "\n")
-               throw("newosproc")
-       }
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-       if mp.waitsema != 0 {
-               return
-       }
-       systemstack(func() {
-               mu := nacl_mutex_create(0)
-               if mu < 0 {
-                       print("nacl_mutex_create: error ", -mu, "\n")
-                       throw("semacreate")
-               }
-               c := nacl_cond_create(0)
-               if c < 0 {
-                       print("nacl_cond_create: error ", -c, "\n")
-                       throw("semacreate")
-               }
-               mp.waitsema = c
-               mp.waitsemalock = mu
-       })
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
-       var ret int32
-
-       systemstack(func() {
-               _g_ := getg()
-               if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
-                       throw("semasleep")
-               }
-
-               for _g_.m.waitsemacount == 0 {
-                       if ns < 0 {
-                               if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
-                                       throw("semasleep")
-                               }
-                       } else {
-                               var ts timespec
-                               end := ns + nanotime()
-                               ts.tv_sec = end / 1e9
-                               ts.tv_nsec = int32(end % 1e9)
-                               r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
-                               if r == -_ETIMEDOUT {
-                                       nacl_mutex_unlock(_g_.m.waitsemalock)
-                                       ret = -1
-                                       return
-                               }
-                               if r < 0 {
-                                       throw("semasleep")
-                               }
-                       }
-               }
-
-               _g_.m.waitsemacount = 0
-               nacl_mutex_unlock(_g_.m.waitsemalock)
-               ret = 0
-       })
-       return ret
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
-       systemstack(func() {
-               if nacl_mutex_lock(mp.waitsemalock) < 0 {
-                       throw("semawakeup")
-               }
-               if mp.waitsemacount != 0 {
-                       throw("semawakeup")
-               }
-               mp.waitsemacount = 1
-               nacl_cond_signal(mp.waitsema)
-               nacl_mutex_unlock(mp.waitsemalock)
-       })
-}
-
-func memlimit() uintptr {
-       return 0
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-//go:norace
-//go:nowritebarrierrec
-func badsignal(sig uintptr) {
-       cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
-}
-
-func badsignalgo(sig uintptr) {
-       if !sigsend(uint32(sig)) {
-               // A foreign thread received the signal sig, and the
-               // Go code does not want to handle it.
-               raisebadsignal(int32(sig))
-       }
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-func badsignal2() {
-       write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
-       exit(2)
-}
-
-var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
-
-func raisebadsignal(sig int32) {
-       badsignal2()
-}
-
-func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
-func munmap(addr unsafe.Pointer, n uintptr)               {}
-func resetcpuprofiler(hz int32)                           {}
-func sigdisable(uint32)                                   {}
-func sigenable(uint32)                                    {}
-func sigignore(uint32)                                    {}
-func closeonexec(int32)                                   {}
-
-var writelock uint32 // test-and-set spin lock for write
-
-/*
-An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
-
-void (*nacl_irt_query)(void);
-
-int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
-void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
-int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
-
-int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
-void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
-int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
-
-int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
-void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
-int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
-*/
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
deleted file mode 100644 (file)
index 447dff8..0000000
+++ /dev/null
@@ -1,278 +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 runtime
-
-import (
-       "runtime/internal/atomic"
-       "unsafe"
-)
-
-const (
-       _ESRCH       = 3
-       _EAGAIN      = 35
-       _EWOULDBLOCK = _EAGAIN
-       _ENOTSUP     = 91
-
-       // From OpenBSD's sys/time.h
-       _CLOCK_REALTIME  = 0
-       _CLOCK_VIRTUAL   = 1
-       _CLOCK_PROF      = 2
-       _CLOCK_MONOTONIC = 3
-)
-
-type sigset uint32
-
-const (
-       sigset_none = sigset(0)
-       sigset_all  = ^sigset(0)
-)
-
-// From OpenBSD's <sys/sysctl.h>
-const (
-       _CTL_HW  = 6
-       _HW_NCPU = 3
-)
-
-func getncpu() int32 {
-       mib := [2]uint32{_CTL_HW, _HW_NCPU}
-       out := uint32(0)
-       nout := unsafe.Sizeof(out)
-
-       // Fetch hw.ncpu via sysctl.
-       ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
-       if ret >= 0 {
-               return int32(out)
-       }
-       return 1
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
-       _g_ := getg()
-
-       // Compute sleep deadline.
-       var tsp *timespec
-       if ns >= 0 {
-               var ts timespec
-               var nsec int32
-               ns += nanotime()
-               ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
-               ts.set_nsec(nsec)
-               tsp = &ts
-       }
-
-       for {
-               v := atomic.Load(&_g_.m.waitsemacount)
-               if v > 0 {
-                       if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
-                               return 0 // semaphore acquired
-                       }
-                       continue
-               }
-
-               // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
-               //
-               // From OpenBSD's __thrsleep(2) manual:
-               // "The abort argument, if not NULL, points to an int that will
-               // be examined [...] immediately before blocking. If that int
-               // is non-zero then __thrsleep() will immediately return EINTR
-               // without blocking."
-               ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
-               if ret == _EWOULDBLOCK {
-                       return -1
-               }
-       }
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
-       atomic.Xadd(&mp.waitsemacount, 1)
-       ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
-       if ret != 0 && ret != _ESRCH {
-               // semawakeup can be called on signal stack.
-               systemstack(func() {
-                       print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
-               })
-       }
-}
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
-       if false {
-               print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
-       }
-
-       param := tforkt{
-               tf_tcb:   unsafe.Pointer(&mp.tls[0]),
-               tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
-               tf_stack: uintptr(stk),
-       }
-
-       oset := sigprocmask(_SIG_SETMASK, sigset_all)
-       ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
-       sigprocmask(_SIG_SETMASK, oset)
-
-       if ret < 0 {
-               print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
-               throw("runtime.newosproc")
-       }
-}
-
-func osinit() {
-       ncpu = getncpu()
-}
-
-var urandom_dev = []byte("/dev/urandom\x00")
-
-//go:nosplit
-func getRandomData(r []byte) {
-       fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
-       n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-       closefd(fd)
-       extendRandom(r, int(n))
-}
-
-func goenvs() {
-       goenvs_unix()
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
-       mp.gsignal = malg(32 * 1024)
-       mp.gsignal.m = mp
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-       mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-       sigprocmask(_SIG_SETMASK, sigmask)
-}
-
-//go:nosplit
-func sigblock() {
-       sigprocmask(_SIG_SETMASK, sigset_all)
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-func minit() {
-       _g_ := getg()
-
-       // m.procid is a uint64, but tfork writes an int32. Fix it up.
-       _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
-
-       // Initialize signal handling
-       var st stackt
-       sigaltstack(nil, &st)
-       if st.ss_flags&_SS_DISABLE != 0 {
-               signalstack(&_g_.m.gsignal.stack)
-               _g_.m.newSigstack = true
-       } else {
-               // Use existing signal stack.
-               stsp := uintptr(unsafe.Pointer(st.ss_sp))
-               _g_.m.gsignal.stack.lo = stsp
-               _g_.m.gsignal.stack.hi = stsp + st.ss_size
-               _g_.m.gsignal.stackguard0 = stsp + _StackGuard
-               _g_.m.gsignal.stackguard1 = stsp + _StackGuard
-               _g_.m.gsignal.stackAlloc = st.ss_size
-               _g_.m.newSigstack = false
-       }
-
-       // restore signal mask from m.sigmask and unblock essential signals
-       nmask := _g_.m.sigmask
-       for i := range sigtable {
-               if sigtable[i].flags&_SigUnblock != 0 {
-                       nmask &^= 1 << (uint32(i) - 1)
-               }
-       }
-       sigprocmask(_SIG_SETMASK, nmask)
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-func unminit() {
-       if getg().m.newSigstack {
-               signalstack(nil)
-       }
-}
-
-func memlimit() uintptr {
-       return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
-       sa_sigaction uintptr
-       sa_mask      uint32
-       sa_flags     int32
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
-       var sa sigactiont
-       sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
-       if restart {
-               sa.sa_flags |= _SA_RESTART
-       }
-       sa.sa_mask = uint32(sigset_all)
-       if fn == funcPC(sighandler) {
-               fn = funcPC(sigtramp)
-       }
-       sa.sa_sigaction = fn
-       sigaction(i, &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-       throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func getsig(i int32) uintptr {
-       var sa sigactiont
-       sigaction(i, nil, &sa)
-       if sa.sa_sigaction == funcPC(sigtramp) {
-               return funcPC(sighandler)
-       }
-       return sa.sa_sigaction
-}
-
-//go:nosplit
-func signalstack(s *stack) {
-       var st stackt
-       if s == nil {
-               st.ss_flags = _SS_DISABLE
-       } else {
-               st.ss_sp = s.lo
-               st.ss_size = s.hi - s.lo
-               st.ss_flags = 0
-       }
-       sigaltstack(&st, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
-       sigprocmask(_SIG_SETMASK, sigset(m[0]))
-}
-
-func unblocksig(sig int32) {
-       mask := sigset(1) << (uint32(sig) - 1)
-       sigprocmask(_SIG_UNBLOCK, mask)
-}
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
deleted file mode 100644 (file)
index 6c7e36d..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import (
-       "runtime/internal/atomic"
-       "unsafe"
-)
-
-type sigset struct{}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
-       // Initialize stack and goroutine for note handling.
-       mp.gsignal = malg(32 * 1024)
-       mp.gsignal.m = mp
-       mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
-       // Initialize stack for handling strings from the
-       // errstr system call, as used in package syscall.
-       mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
-}
-
-func msigsave(mp *m) {
-}
-
-func msigrestore(sigmask sigset) {
-}
-
-func sigblock() {
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
-       if atomic.Load(&exiting) != 0 {
-               exits(&emptystatus[0])
-       }
-       // Mask all SSE floating-point exceptions
-       // when running on the 64-bit kernel.
-       setfpmasks()
-}
-
-// Called from dropm to undo the effect of an minit.
-func unminit() {
-}
-
-var sysstat = []byte("/dev/sysstat\x00")
-
-func getproccount() int32 {
-       var buf [2048]byte
-       fd := open(&sysstat[0], _OREAD, 0)
-       if fd < 0 {
-               return 1
-       }
-       ncpu := int32(0)
-       for {
-               n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
-               if n <= 0 {
-                       break
-               }
-               for i := int32(0); i < n; i++ {
-                       if buf[i] == '\n' {
-                               ncpu++
-                       }
-               }
-       }
-       closefd(fd)
-       if ncpu == 0 {
-               ncpu = 1
-       }
-       return ncpu
-}
-
-var pid = []byte("#c/pid\x00")
-
-func getpid() uint64 {
-       var b [20]byte
-       fd := open(&pid[0], 0, 0)
-       if fd >= 0 {
-               read(fd, unsafe.Pointer(&b), int32(len(b)))
-               closefd(fd)
-       }
-       c := b[:]
-       for c[0] == ' ' || c[0] == '\t' {
-               c = c[1:]
-       }
-       return uint64(_atoi(c))
-}
-
-func osinit() {
-       initBloc()
-       ncpu = getproccount()
-       getg().m.procid = getpid()
-       notify(unsafe.Pointer(funcPC(sigtramp)))
-}
-
-func crash() {
-       notify(nil)
-       *(*int)(nil) = 0
-}
-
-//go:nosplit
-func getRandomData(r []byte) {
-       extendRandom(r, 0)
-}
-
-func goenvs() {
-}
-
-func initsig(preinit bool) {
-}
-
-//go:nosplit
-func osyield() {
-       sleep(0)
-}
-
-//go:nosplit
-func usleep(µs uint32) {
-       ms := int32(µs / 1000)
-       if ms == 0 {
-               ms = 1
-       }
-       sleep(ms)
-}
-
-//go:nosplit
-func nanotime() int64 {
-       var scratch int64
-       ns := nsec(&scratch)
-       // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
-       if ns == 0 {
-               return scratch
-       }
-       return ns
-}
-
-//go:nosplit
-func itoa(buf []byte, val uint64) []byte {
-       i := len(buf) - 1
-       for val >= 10 {
-               buf[i] = byte(val%10 + '0')
-               i--
-               val /= 10
-       }
-       buf[i] = byte(val + '0')
-       return buf[i:]
-}
-
-var goexits = []byte("go: exit ")
-var emptystatus = []byte("\x00")
-var exiting uint32
-
-func goexitsall(status *byte) {
-       var buf [_ERRMAX]byte
-       if !atomic.Cas(&exiting, 0, 1) {
-               return
-       }
-       getg().m.locks++
-       n := copy(buf[:], goexits)
-       n = copy(buf[n:], gostringnocopy(status))
-       pid := getpid()
-       for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
-               if mp.procid != 0 && mp.procid != pid {
-                       postnote(mp.procid, buf[:])
-               }
-       }
-       getg().m.locks--
-}
-
-var procdir = []byte("/proc/")
-var notefile = []byte("/note\x00")
-
-func postnote(pid uint64, msg []byte) int {
-       var buf [128]byte
-       var tmp [32]byte
-       n := copy(buf[:], procdir)
-       n += copy(buf[n:], itoa(tmp[:], pid))
-       copy(buf[n:], notefile)
-       fd := open(&buf[0], _OWRITE, 0)
-       if fd < 0 {
-               return -1
-       }
-       len := findnull(&msg[0])
-       if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
-               closefd(fd)
-               return -1
-       }
-       closefd(fd)
-       return 0
-}
-
-//go:nosplit
-func exit(e int) {
-       var status []byte
-       if e == 0 {
-               status = emptystatus
-       } else {
-               // build error string
-               var tmp [32]byte
-               status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
-       }
-       goexitsall(&status[0])
-       exits(&status[0])
-}
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
-       if false {
-               print("newosproc mp=", mp, " ostk=", &mp, "\n")
-       }
-       pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
-       if pid < 0 {
-               throw("newosproc: rfork failed")
-       }
-       if pid == 0 {
-               tstart_plan9(mp)
-       }
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-}
-
-//go:nosplit
-func semasleep(ns int64) int {
-       _g_ := getg()
-       if ns >= 0 {
-               ms := timediv(ns, 1000000, nil)
-               if ms == 0 {
-                       ms = 1
-               }
-               ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
-               if ret == 1 {
-                       return 0 // success
-               }
-               return -1 // timeout or interrupted
-       }
-       for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
-               // interrupted; try again (c.f. lock_sema.go)
-       }
-       return 0 // success
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
-       plan9_semrelease(&mp.waitsemacount, 1)
-}
-
-//go:nosplit
-func read(fd int32, buf unsafe.Pointer, n int32) int32 {
-       return pread(fd, buf, n, -1)
-}
-
-//go:nosplit
-func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
-       return int64(pwrite(int32(fd), buf, n, -1))
-}
-
-func memlimit() uint64 {
-       return 0
-}
-
-var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-func badsignal2() {
-       pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
-       exits(&_badsignal[0])
-}
-
-func raisebadsignal(sig int32) {
-       badsignal2()
-}
-
-func _atoi(b []byte) int {
-       n := 0
-       for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
-               n = n*10 + int(b[0]) - '0'
-               b = b[1:]
-       }
-       return n
-}
-
-func signame(sig uint32) string {
-       if sig >= uint32(len(sigtable)) {
-               return ""
-       }
-       return sigtable[sig].name
-}
index 44830650e12952df60a0d008c351a4fbf79b0cd5..3a73b6627743e37bfdca36b1a183c2fead042ff3 100644 (file)
@@ -1,10 +1,13 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// 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 runtime
 
-import "unsafe"
+import (
+       "runtime/internal/sys"
+       "unsafe"
+)
 
 type mOS struct{}
 
@@ -35,3 +38,274 @@ func raiseproc(sig int32)
 func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
 
 func osyield()
+
+// From FreeBSD's <sys/sysctl.h>
+const (
+       _CTL_HW  = 6
+       _HW_NCPU = 3
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+       mib := [2]uint32{_CTL_HW, _HW_NCPU}
+       out := uint32(0)
+       nout := unsafe.Sizeof(out)
+       ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+       if ret >= 0 {
+               return int32(out)
+       }
+       return 1
+}
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See Linux implementation
+// and lock_futex.go for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+       systemstack(func() {
+               futexsleep1(addr, val, ns)
+       })
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+       var tsp *timespec
+       if ns >= 0 {
+               var ts timespec
+               ts.tv_nsec = 0
+               ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+               tsp = &ts
+       }
+       ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+       if ret >= 0 || ret == -_EINTR {
+               return
+       }
+       print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+       *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+       ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+       if ret >= 0 {
+               return
+       }
+
+       systemstack(func() {
+               print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+       })
+}
+
+func thr_start()
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+       if false {
+               print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
+       }
+
+       // NOTE(rsc): This code is confused. stackbase is the top of the stack
+       // and is equal to stk. However, it's working, so I'm not changing it.
+       param := thrparam{
+               start_func: funcPC(thr_start),
+               arg:        unsafe.Pointer(mp),
+               stack_base: mp.g0.stack.hi,
+               stack_size: uintptr(stk) - mp.g0.stack.hi,
+               child_tid:  unsafe.Pointer(&mp.procid),
+               parent_tid: nil,
+               tls_base:   unsafe.Pointer(&mp.tls[0]),
+               tls_size:   unsafe.Sizeof(mp.tls),
+       }
+
+       var oset sigset
+       sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+       thr_new(&param, int32(unsafe.Sizeof(param)))
+       sigprocmask(_SIG_SETMASK, &oset, nil)
+}
+
+func osinit() {
+       ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+       fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+       n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+       closefd(fd)
+       extendRandom(r, int(n))
+}
+
+func goenvs() {
+       goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+       mp.gsignal = malg(32 * 1024)
+       mp.gsignal.m = mp
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+       sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+       sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+       _g_ := getg()
+
+       // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
+       // Fix it up. (Only matters on big-endian, but be clean anyway.)
+       if sys.PtrSize == 4 {
+               _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
+       }
+
+       // Initialize signal handling.
+       var st stackt
+       sigaltstack(nil, &st)
+       if st.ss_flags&_SS_DISABLE != 0 {
+               signalstack(&_g_.m.gsignal.stack)
+               _g_.m.newSigstack = true
+       } else {
+               // Use existing signal stack.
+               stsp := uintptr(unsafe.Pointer(st.ss_sp))
+               _g_.m.gsignal.stack.lo = stsp
+               _g_.m.gsignal.stack.hi = stsp + st.ss_size
+               _g_.m.gsignal.stackguard0 = stsp + _StackGuard
+               _g_.m.gsignal.stackguard1 = stsp + _StackGuard
+               _g_.m.gsignal.stackAlloc = st.ss_size
+               _g_.m.newSigstack = false
+       }
+
+       // restore signal mask from m.sigmask and unblock essential signals
+       nmask := _g_.m.sigmask
+       for i := range sigtable {
+               if sigtable[i].flags&_SigUnblock != 0 {
+                       nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+               }
+       }
+       sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+       if getg().m.newSigstack {
+               signalstack(nil)
+       }
+}
+
+func memlimit() uintptr {
+       /*
+               TODO: Convert to Go when something actually uses the result.
+               Rlimit rl;
+               extern byte runtime·text[], runtime·end[];
+               uintptr used;
+
+               if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+                       return 0;
+               if(rl.rlim_cur >= 0x7fffffff)
+                       return 0;
+
+               // Estimate our VM footprint excluding the heap.
+               // Not an exact science: use size of binary plus
+               // some room for thread stacks.
+               used = runtime·end - runtime·text + (64<<20);
+               if(used >= rl.rlim_cur)
+                       return 0;
+
+               // If there's not at least 16 MB left, we're probably
+               // not going to be able to do much. Treat as no limit.
+               rl.rlim_cur -= used;
+               if(rl.rlim_cur < (16<<20))
+                       return 0;
+
+               return rl.rlim_cur - used;
+       */
+
+       return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+       sa_handler uintptr
+       sa_flags   int32
+       sa_mask    sigset
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i int32, fn uintptr, restart bool) {
+       var sa sigactiont
+       sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+       if restart {
+               sa.sa_flags |= _SA_RESTART
+       }
+       sa.sa_mask = sigset_all
+       if fn == funcPC(sighandler) {
+               fn = funcPC(sigtramp)
+       }
+       sa.sa_handler = fn
+       sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+       throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+       var sa sigactiont
+       sigaction(i, nil, &sa)
+       if sa.sa_handler == funcPC(sigtramp) {
+               return funcPC(sighandler)
+       }
+       return sa.sa_handler
+}
+
+//go:nosplit
+func signalstack(s *stack) {
+       var st stackt
+       if s == nil {
+               st.ss_flags = _SS_DISABLE
+       } else {
+               st.ss_sp = s.lo
+               st.ss_size = s.hi - s.lo
+               st.ss_flags = 0
+       }
+       sigaltstack(&st, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
+       var mask sigset
+       copy(mask.__bits[:], m[:])
+       sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+       var mask sigset
+       mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+       sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
index 92b5c82af7c20fa9e125c835eb66b0be0d2ee589..8039b2fac9b7a34de683d8dd41e9b20df7e8b51f 100644 (file)
@@ -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().
index 0b46f594ce011765737839ebe899e7639cd6032c..22522dd803dc02704b9e27c91c1bd9027689a5d0 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!arm,!arm64
+// +build !amd64,!arm,!arm64,!mips64,!mips64le
 
 package runtime
 
index 6f126b4770505e4fed38971d96da9ae5f765b4b8..6cbd16de159c8c24a709efcbcc082a0b046c53e5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2010 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.
 
@@ -67,3 +67,233 @@ func raiseproc(sig int32) {
 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).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+       mp.gsignal = malg(32 * 1024)
+       mp.gsignal.m = mp
+}
+
+func sigtramp()
+
+//go:nosplit
+func msigsave(mp *m) {
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+       _g_ := getg()
+
+       // Initialize signal handling
+       ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
+       if ret < 0 {
+               print("runtime: nacl_exception_stack: error ", -ret, "\n")
+       }
+
+       ret = nacl_exception_handler(funcPC(sigtramp), nil)
+       if ret < 0 {
+               print("runtime: nacl_exception_handler: error ", -ret, "\n")
+       }
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+func osinit() {
+       ncpu = 1
+       getg().m.procid = 2
+       //nacl_exception_handler(funcPC(sigtramp), nil);
+}
+
+func signame(sig uint32) string {
+       if sig >= uint32(len(sigtable)) {
+               return ""
+       }
+       return sigtable[sig].name
+}
+
+func crash() {
+       *(*int32)(nil) = 0
+}
+
+//go:noescape
+func getRandomData([]byte)
+
+func goenvs() {
+       goenvs_unix()
+}
+
+func initsig(preinit bool) {
+}
+
+//go:nosplit
+func usleep(us uint32) {
+       var ts timespec
+
+       ts.tv_sec = int64(us / 1e6)
+       ts.tv_nsec = int32(us%1e6) * 1e3
+       nacl_nanosleep(&ts, nil)
+}
+
+func mstart_nacl()
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+       mp.tls[0] = uintptr(unsafe.Pointer(mp.g0))
+       mp.tls[1] = uintptr(unsafe.Pointer(mp))
+       ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&mp.tls[2]), nil)
+       if ret < 0 {
+               print("nacl_thread_create: error ", -ret, "\n")
+               throw("newosproc")
+       }
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+       if mp.waitsema != 0 {
+               return
+       }
+       systemstack(func() {
+               mu := nacl_mutex_create(0)
+               if mu < 0 {
+                       print("nacl_mutex_create: error ", -mu, "\n")
+                       throw("semacreate")
+               }
+               c := nacl_cond_create(0)
+               if c < 0 {
+                       print("nacl_cond_create: error ", -c, "\n")
+                       throw("semacreate")
+               }
+               mp.waitsema = c
+               mp.waitsemalock = mu
+       })
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+       var ret int32
+
+       systemstack(func() {
+               _g_ := getg()
+               if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
+                       throw("semasleep")
+               }
+
+               for _g_.m.waitsemacount == 0 {
+                       if ns < 0 {
+                               if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
+                                       throw("semasleep")
+                               }
+                       } else {
+                               var ts timespec
+                               end := ns + nanotime()
+                               ts.tv_sec = end / 1e9
+                               ts.tv_nsec = int32(end % 1e9)
+                               r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
+                               if r == -_ETIMEDOUT {
+                                       nacl_mutex_unlock(_g_.m.waitsemalock)
+                                       ret = -1
+                                       return
+                               }
+                               if r < 0 {
+                                       throw("semasleep")
+                               }
+                       }
+               }
+
+               _g_.m.waitsemacount = 0
+               nacl_mutex_unlock(_g_.m.waitsemalock)
+               ret = 0
+       })
+       return ret
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+       systemstack(func() {
+               if nacl_mutex_lock(mp.waitsemalock) < 0 {
+                       throw("semawakeup")
+               }
+               if mp.waitsemacount != 0 {
+                       throw("semawakeup")
+               }
+               mp.waitsemacount = 1
+               nacl_cond_signal(mp.waitsema)
+               nacl_mutex_unlock(mp.waitsemalock)
+       })
+}
+
+func memlimit() uintptr {
+       return 0
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr) {
+       cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+}
+
+func badsignalgo(sig uintptr) {
+       if !sigsend(uint32(sig)) {
+               // A foreign thread received the signal sig, and the
+               // Go code does not want to handle it.
+               raisebadsignal(int32(sig))
+       }
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+       write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
+       exit(2)
+}
+
+var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
+
+func raisebadsignal(sig int32) {
+       badsignal2()
+}
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
+func munmap(addr unsafe.Pointer, n uintptr)               {}
+func resetcpuprofiler(hz int32)                           {}
+func sigdisable(uint32)                                   {}
+func sigenable(uint32)                                    {}
+func sigignore(uint32)                                    {}
+func closeonexec(int32)                                   {}
+
+var writelock uint32 // test-and-set spin lock for write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*nacl_irt_query)(void);
+
+int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
+
+int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
+
+int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
+*/
index 3748ed2e514cc1dd2c465b20961ae9a3032050af..ded6b1d4ea4a83ead841790e890c4e255278b3ac 100644 (file)
@@ -1,9 +1,14 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// 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 runtime
 
+import (
+       "runtime/internal/atomic"
+       "unsafe"
+)
+
 type mOS struct {
        waitsemacount uint32
 }
@@ -36,3 +41,271 @@ func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort
 func thrwakeup(ident uintptr, n int32) int32
 
 func osyield()
+
+const (
+       _ESRCH       = 3
+       _EAGAIN      = 35
+       _EWOULDBLOCK = _EAGAIN
+       _ENOTSUP     = 91
+
+       // From OpenBSD's sys/time.h
+       _CLOCK_REALTIME  = 0
+       _CLOCK_VIRTUAL   = 1
+       _CLOCK_PROF      = 2
+       _CLOCK_MONOTONIC = 3
+)
+
+type sigset uint32
+
+const (
+       sigset_none = sigset(0)
+       sigset_all  = ^sigset(0)
+)
+
+// From OpenBSD's <sys/sysctl.h>
+const (
+       _CTL_HW  = 6
+       _HW_NCPU = 3
+)
+
+func getncpu() int32 {
+       mib := [2]uint32{_CTL_HW, _HW_NCPU}
+       out := uint32(0)
+       nout := unsafe.Sizeof(out)
+
+       // Fetch hw.ncpu via sysctl.
+       ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+       if ret >= 0 {
+               return int32(out)
+       }
+       return 1
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+       _g_ := getg()
+
+       // Compute sleep deadline.
+       var tsp *timespec
+       if ns >= 0 {
+               var ts timespec
+               var nsec int32
+               ns += nanotime()
+               ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+               ts.set_nsec(nsec)
+               tsp = &ts
+       }
+
+       for {
+               v := atomic.Load(&_g_.m.waitsemacount)
+               if v > 0 {
+                       if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
+                               return 0 // semaphore acquired
+                       }
+                       continue
+               }
+
+               // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
+               //
+               // From OpenBSD's __thrsleep(2) manual:
+               // "The abort argument, if not NULL, points to an int that will
+               // be examined [...] immediately before blocking. If that int
+               // is non-zero then __thrsleep() will immediately return EINTR
+               // without blocking."
+               ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
+               if ret == _EWOULDBLOCK {
+                       return -1
+               }
+       }
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+       atomic.Xadd(&mp.waitsemacount, 1)
+       ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
+       if ret != 0 && ret != _ESRCH {
+               // semawakeup can be called on signal stack.
+               systemstack(func() {
+                       print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+               })
+       }
+}
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+       if false {
+               print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
+       }
+
+       param := tforkt{
+               tf_tcb:   unsafe.Pointer(&mp.tls[0]),
+               tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
+               tf_stack: uintptr(stk),
+       }
+
+       oset := sigprocmask(_SIG_SETMASK, sigset_all)
+       ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
+       sigprocmask(_SIG_SETMASK, oset)
+
+       if ret < 0 {
+               print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+               throw("runtime.newosproc")
+       }
+}
+
+func osinit() {
+       ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+       fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+       n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+       closefd(fd)
+       extendRandom(r, int(n))
+}
+
+func goenvs() {
+       goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+       mp.gsignal = malg(32 * 1024)
+       mp.gsignal.m = mp
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+       mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+       sigprocmask(_SIG_SETMASK, sigmask)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, sigset_all)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+       _g_ := getg()
+
+       // m.procid is a uint64, but tfork writes an int32. Fix it up.
+       _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+       // Initialize signal handling
+       var st stackt
+       sigaltstack(nil, &st)
+       if st.ss_flags&_SS_DISABLE != 0 {
+               signalstack(&_g_.m.gsignal.stack)
+               _g_.m.newSigstack = true
+       } else {
+               // Use existing signal stack.
+               stsp := uintptr(unsafe.Pointer(st.ss_sp))
+               _g_.m.gsignal.stack.lo = stsp
+               _g_.m.gsignal.stack.hi = stsp + st.ss_size
+               _g_.m.gsignal.stackguard0 = stsp + _StackGuard
+               _g_.m.gsignal.stackguard1 = stsp + _StackGuard
+               _g_.m.gsignal.stackAlloc = st.ss_size
+               _g_.m.newSigstack = false
+       }
+
+       // restore signal mask from m.sigmask and unblock essential signals
+       nmask := _g_.m.sigmask
+       for i := range sigtable {
+               if sigtable[i].flags&_SigUnblock != 0 {
+                       nmask &^= 1 << (uint32(i) - 1)
+               }
+       }
+       sigprocmask(_SIG_SETMASK, nmask)
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+       if getg().m.newSigstack {
+               signalstack(nil)
+       }
+}
+
+func memlimit() uintptr {
+       return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+       sa_sigaction uintptr
+       sa_mask      uint32
+       sa_flags     int32
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i int32, fn uintptr, restart bool) {
+       var sa sigactiont
+       sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+       if restart {
+               sa.sa_flags |= _SA_RESTART
+       }
+       sa.sa_mask = uint32(sigset_all)
+       if fn == funcPC(sighandler) {
+               fn = funcPC(sigtramp)
+       }
+       sa.sa_sigaction = fn
+       sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+       throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+       var sa sigactiont
+       sigaction(i, nil, &sa)
+       if sa.sa_sigaction == funcPC(sigtramp) {
+               return funcPC(sighandler)
+       }
+       return sa.sa_sigaction
+}
+
+//go:nosplit
+func signalstack(s *stack) {
+       var st stackt
+       if s == nil {
+               st.ss_flags = _SS_DISABLE
+       } else {
+               st.ss_sp = s.lo
+               st.ss_size = s.hi - s.lo
+               st.ss_flags = 0
+       }
+       sigaltstack(&st, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+       sigprocmask(_SIG_SETMASK, sigset(m[0]))
+}
+
+func unblocksig(sig int32) {
+       mask := sigset(1) << (uint32(sig) - 1)
+       sigprocmask(_SIG_UNBLOCK, mask)
+}
index 5c43a3bd854b34cc4c1f58b2b582c2e87fa3ff89..2f3a0d1a19b2fd285f8167a80eadd6a112bda913 100644 (file)
@@ -1,10 +1,13 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2010 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
 package runtime
 
-import "unsafe"
+import (
+       "runtime/internal/atomic"
+       "unsafe"
+)
 
 type mOS struct {
        waitsemacount uint32
@@ -148,3 +151,288 @@ func atolwhex(p string) int64 {
        }
        return n
 }
+
+type sigset struct{}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+       // Initialize stack and goroutine for note handling.
+       mp.gsignal = malg(32 * 1024)
+       mp.gsignal.m = mp
+       mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
+       // Initialize stack for handling strings from the
+       // errstr system call, as used in package syscall.
+       mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
+}
+
+func msigsave(mp *m) {
+}
+
+func msigrestore(sigmask sigset) {
+}
+
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+       if atomic.Load(&exiting) != 0 {
+               exits(&emptystatus[0])
+       }
+       // Mask all SSE floating-point exceptions
+       // when running on the 64-bit kernel.
+       setfpmasks()
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+var sysstat = []byte("/dev/sysstat\x00")
+
+func getproccount() int32 {
+       var buf [2048]byte
+       fd := open(&sysstat[0], _OREAD, 0)
+       if fd < 0 {
+               return 1
+       }
+       ncpu := int32(0)
+       for {
+               n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
+               if n <= 0 {
+                       break
+               }
+               for i := int32(0); i < n; i++ {
+                       if buf[i] == '\n' {
+                               ncpu++
+                       }
+               }
+       }
+       closefd(fd)
+       if ncpu == 0 {
+               ncpu = 1
+       }
+       return ncpu
+}
+
+var pid = []byte("#c/pid\x00")
+
+func getpid() uint64 {
+       var b [20]byte
+       fd := open(&pid[0], 0, 0)
+       if fd >= 0 {
+               read(fd, unsafe.Pointer(&b), int32(len(b)))
+               closefd(fd)
+       }
+       c := b[:]
+       for c[0] == ' ' || c[0] == '\t' {
+               c = c[1:]
+       }
+       return uint64(_atoi(c))
+}
+
+func osinit() {
+       initBloc()
+       ncpu = getproccount()
+       getg().m.procid = getpid()
+       notify(unsafe.Pointer(funcPC(sigtramp)))
+}
+
+func crash() {
+       notify(nil)
+       *(*int)(nil) = 0
+}
+
+//go:nosplit
+func getRandomData(r []byte) {
+       extendRandom(r, 0)
+}
+
+func goenvs() {
+}
+
+func initsig(preinit bool) {
+}
+
+//go:nosplit
+func osyield() {
+       sleep(0)
+}
+
+//go:nosplit
+func usleep(µs uint32) {
+       ms := int32(µs / 1000)
+       if ms == 0 {
+               ms = 1
+       }
+       sleep(ms)
+}
+
+//go:nosplit
+func nanotime() int64 {
+       var scratch int64
+       ns := nsec(&scratch)
+       // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+       if ns == 0 {
+               return scratch
+       }
+       return ns
+}
+
+//go:nosplit
+func itoa(buf []byte, val uint64) []byte {
+       i := len(buf) - 1
+       for val >= 10 {
+               buf[i] = byte(val%10 + '0')
+               i--
+               val /= 10
+       }
+       buf[i] = byte(val + '0')
+       return buf[i:]
+}
+
+var goexits = []byte("go: exit ")
+var emptystatus = []byte("\x00")
+var exiting uint32
+
+func goexitsall(status *byte) {
+       var buf [_ERRMAX]byte
+       if !atomic.Cas(&exiting, 0, 1) {
+               return
+       }
+       getg().m.locks++
+       n := copy(buf[:], goexits)
+       n = copy(buf[n:], gostringnocopy(status))
+       pid := getpid()
+       for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+               if mp.procid != 0 && mp.procid != pid {
+                       postnote(mp.procid, buf[:])
+               }
+       }
+       getg().m.locks--
+}
+
+var procdir = []byte("/proc/")
+var notefile = []byte("/note\x00")
+
+func postnote(pid uint64, msg []byte) int {
+       var buf [128]byte
+       var tmp [32]byte
+       n := copy(buf[:], procdir)
+       n += copy(buf[n:], itoa(tmp[:], pid))
+       copy(buf[n:], notefile)
+       fd := open(&buf[0], _OWRITE, 0)
+       if fd < 0 {
+               return -1
+       }
+       len := findnull(&msg[0])
+       if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
+               closefd(fd)
+               return -1
+       }
+       closefd(fd)
+       return 0
+}
+
+//go:nosplit
+func exit(e int) {
+       var status []byte
+       if e == 0 {
+               status = emptystatus
+       } else {
+               // build error string
+               var tmp [32]byte
+               status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
+       }
+       goexitsall(&status[0])
+       exits(&status[0])
+}
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+       if false {
+               print("newosproc mp=", mp, " ostk=", &mp, "\n")
+       }
+       pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
+       if pid < 0 {
+               throw("newosproc: rfork failed")
+       }
+       if pid == 0 {
+               tstart_plan9(mp)
+       }
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int {
+       _g_ := getg()
+       if ns >= 0 {
+               ms := timediv(ns, 1000000, nil)
+               if ms == 0 {
+                       ms = 1
+               }
+               ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
+               if ret == 1 {
+                       return 0 // success
+               }
+               return -1 // timeout or interrupted
+       }
+       for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
+               // interrupted; try again (c.f. lock_sema.go)
+       }
+       return 0 // success
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+       plan9_semrelease(&mp.waitsemacount, 1)
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, n int32) int32 {
+       return pread(fd, buf, n, -1)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
+       return int64(pwrite(int32(fd), buf, n, -1))
+}
+
+func memlimit() uint64 {
+       return 0
+}
+
+var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+       pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
+       exits(&_badsignal[0])
+}
+
+func raisebadsignal(sig int32) {
+       badsignal2()
+}
+
+func _atoi(b []byte) int {
+       n := 0
+       for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
+               n = n*10 + int(b[0]) - '0'
+               b = b[1:]
+       }
+       return n
+}
+
+func signame(sig uint32) string {
+       if sig >= uint32(len(sigtable)) {
+               return ""
+       }
+       return sigtable[sig].name
+}
index 8b2f3d5291ee12a9d611432d9dfa349978415c75..3852d93e7264c6d98d493772a82416857b3fc0c4 100644 (file)
@@ -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)
                }
index d7e51d7deb872ad025bb83e0b0c089250b81ddae..727c991a577c1c955631bde6e41ef613e9e5465f 100644 (file)
@@ -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")
@@ -273,7 +267,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)
        })
 }
 
@@ -440,9 +434,6 @@ func schedinit() {
 
        sched.maxmcount = 10000
 
-       // Cache the framepointer experiment. This affects stack unwinding.
-       framepointer_enabled = haveexperiment("framepointer")
-
        tracebackinit()
        moduledataverify()
        stackinit()
@@ -533,7 +524,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 +541,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()
        }
@@ -792,7 +783,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 +824,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)
@@ -1835,7 +1826,7 @@ top:
        }
        if fingwait && fingwake {
                if gp := wakefing(); gp != nil {
-                       ready(gp, 0)
+                       ready(gp, 0, true)
                }
        }
 
@@ -2445,7 +2436,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
@@ -4164,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 := ""
@@ -4176,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
 }
index 899412107199545a5379c76724291380026d69f0..22e4dca771c6c0d1f109919000a2285ceaa8bf08 100644 (file)
@@ -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"
index ecd68d80ce524975306fb92648a1852fa3b80734..42da936ddbf69581c2e1b2f4b48e854f3aa6fdcf 100644 (file)
@@ -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)
 }
 
index cddd9a6e782f2a2e5d0aded50f9032225baf7eef..449191639e6180867ad4583f331b10e567e30229 100644 (file)
@@ -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) {
index ad46fd406dc208f9522c1eb39ded4072162a7892..655e77a86bde7269ae3d0ba583e2e130bc5a57b2 100644 (file)
@@ -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
index 59733d3ff60fe05d1ba4cb474549587f3bb730c4..526d88f13d2430d8f21a3a5dff0ae648312b7a07 100644 (file)
@@ -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
 
 
index a4419b898e31ef5a85ff5a65ac5e5b86ea7a3731..597e642adb717786958c31c945c180fec869d1b2 100644 (file)
@@ -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
index ac7b9225a43bef982954fd952ce639240c709f9c..2c5541357f2af77c896bf9471ea7bca19a7330af 100644 (file)
@@ -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
index 4f82646dbbe7f7e4c64aa2ebc41e06f48b8ce5b5..aabe52da3c42312c96fb0382a64867ef7eb23987 100644 (file)
@@ -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 (
@@ -98,7 +102,9 @@ 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", "set python print-stack full",
                "-ex", "br main.go:10",
                "-ex", "run",
                "-ex", "echo BEGIN info goroutines\n",
@@ -205,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)
@@ -226,6 +236,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",
index 2bd91c1ec03893f3f03857dd0cf6f3659f97de81..4c379b9cdc28b7a08ea1778606776263b0ff0aaa 100644 (file)
@@ -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)
index e19c7fe93248bc98f1f6a76bb8d70aa53c015b7c..3c9eed5905c53eef57e74a83dc6bbedf5c4da4e2 100644 (file)
@@ -508,7 +508,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)
@@ -521,6 +521,6 @@ func reflect_addReflectOff(ptr unsafe.Pointer) int32 {
                reflectOffs.m[id] = ptr
                reflectOffs.minv[ptr] = id
        }
-       unlock(&reflectOffs.lock)
+       reflectOffsUnlock()
        return id
 }
index 71da504f1c0e193cabf0c2ddf6e7f0dfae80197e..6119e75203c457c2a985ab9a1a22f1b145267ec2 100644 (file)
@@ -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.
index 31c1f2c4e58e9347fb64d5f83caf20ce65bd4a7c..5080202833e3d8fd16fcd381a8aae262303f06a1 100644 (file)
@@ -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)
 }
 
index 648b2e1169cffb8dec7330b4fdf146bb05c585c0..5f609c80d3ebae5924d5ae2e5be1f547f492a534 100644 (file)
@@ -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)))
index f68c513fd67e39ce00b40f765b0519f0a86121ed..ee2797e14433007c8edfdcc8d50d0b390833aadc 100644 (file)
@@ -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")
@@ -254,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")
@@ -275,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")
@@ -293,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")
@@ -311,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.
@@ -408,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)
@@ -1010,7 +1023,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
index f80a85fb67767b327b534cb5d6481e5d1a4d3d2c..2bb818f456ea2e358160d87c706acdc187636594 100644 (file)
@@ -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));
index d550a818ce85f1632375f808706bf5d0bf4560f9..9c197379fb8f421e11523ef7e49bc3cbcee7c6bf 100644 (file)
@@ -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
index 0676e9a4eccd2a0f23181f8a607796ae449fe451..a0c1f82b56bd6242f47ee5a501bbe10b482f8477 100644 (file)
@@ -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")
+}
index 7926908828ba85f31303b45d9fe14b8cdb2104e8..2ccbada57b3c1a474529c6ad06a7f039da062290 100644 (file)
@@ -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)
 }
index 6f896634a6d94655e997f9c8fbb305212996999d..ba66d0f5c9564f9adbd1ddcc7e54389decf122d3 100644 (file)
@@ -8,7 +8,7 @@
 
 void gopanic(void);
 
-static unsigned int
+static unsigned int __attribute__((__stdcall__))
 die(void* x)
 {
        gopanic();
index 7771426ef95e9736d2e35d26d039032e5fc07858..279fb52fc0c4e3044e48b1523cbecd05e7ce6cab 100644 (file)
@@ -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.
@@ -251,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
@@ -1034,7 +1040,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
index 608c601abd2973740aed2dea58a19dfdf21fd25f..d7ec5573a9d851c921e81faaa234529d6a883d39 100644 (file)
@@ -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 {
index e254837c63b96ad96386563d233f7afa37b40475..6c1a5064c0d5ef25dce3a54d8bb7a1f312d7df56 100644 (file)
@@ -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")
index 55bf2d2f6fc77a05eb4f3f7dbecbefb121b1c80f..91b29ce358fa6d805d93dcf02a02a16d107bd880 100644 (file)
@@ -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 {
index 1ed803bf8502e7c24bd57123c233fb096175a1e1..6bd6fb5443d31f72cf24e21d563e4b7c4df3b470 100644 (file)
@@ -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{}) }},
 }
 
@@ -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) {
index ab3aa11285478f214bad966f018dee3ab8c2bc1a..30abf726344e96f3955df6101fbdc468ab44a3d9 100644 (file)
@@ -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() {}
index f711c39da2d856c580dbb4494c3f031dc2440382..c070d9d84ef9e5ba39ecca820e747028d55c77ad 100644 (file)
@@ -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() {}
index 78b115cf5a197279717838c4a24138b815cb1669..90892793f0a99cfa112e3f7f386cc24876aef695 100644 (file)
@@ -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
index 2acf505f3c96b90da8c60ddded56540bc4638239..bf29d88c5cb6ccfb926d8735c934c482c54d3e2c 100644 (file)
@@ -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
 
index 9fc6e3bd2c5151ec27cac36295962123e96a0716..455d412330034ed89b9feafea451e60b4bc86858 100644 (file)
@@ -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
index 029e6077cde7144b321cd1c8d90fe339cd26a4fc..b386e1fec2b61ab68c0e0cafc5a9012e6ec7e7fe 100644 (file)
@@ -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
index 2523e9b001a560e052718ade1a06cce2abcc21e3..8b587559edbcba0ba9f2c564eb83d4c0b16ae1b9 100644 (file)
@@ -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 {
index e49bad75b284ff3bdd08646317868cb508020f5f..5a6b2049970901165ab500b2606699ed03386763 100644 (file)
@@ -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))
index eb32cfd4b1e46c7299781c64c39afdd66df102b0..099756328c9cb4f539d4ca8fba4d3ebc62bdfd95 100644 (file)
@@ -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("cat", "/proc/net/dev")
+       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) != 3 {
+               t.Fatalf("Expected 3 lines of output, got %d", len(lines))
+       }
+}
index bccea5105cb7bb2266760a55c3b4fc63ae0fbb40..6551bcb1c1f21570d767751fe040a51eba44b646 100644 (file)
@@ -12,55 +12,44 @@ 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.
+// 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,64 +93,20 @@ 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 {
-                               return nil, ErrBadStat
-                       }
-
-                       s, _, ok := gstring(buf[i+41:])
-                       if !ok {
+               for b := buf[:n]; len(b) > 0; {
+                       var s []byte
+                       s, b = gdirname(b)
+                       if s == nil {
                                return nil, ErrBadStat
                        }
-                       names = append(names, s)
-                       i += int(m)
+                       names = append(names, string(s))
                }
        }
        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
-}
-
-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 +119,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 +129,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 +165,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 <N> is named <N>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 +285,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 +305,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 {
@@ -430,62 +417,23 @@ 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 {
                        Close(p[0])
                        Close(p[1])
                }
-               ForkLock.Unlock()
                return 0, err
        }
-       ForkLock.Unlock()
 
        // Read child error status from pipe.
        Close(p[1])
@@ -493,8 +441,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
index 715992b1bfc684cd58c4b4ae48010e926952d6db..e559793c8b80e7727efd24dad4ff7794ed7d2a93 100644 (file)
@@ -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
 }
 
index 4019fad1a5d1e65a1d64347b972895d9594b0bb5..cbd9539c92cab3eb047c1f43638a3e161b2c207f 100644 (file)
@@ -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 {
index 4a6aa2d6eb5329a08ea74c450be9f6f87bed4303..b89239eba8a4576cc60945d59bed9cf27868cc49 100644 (file)
@@ -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))
index a6cef6fca79e93bbaf1f7e62a5de1cefa100efde..1e0d9401e746f425158c2198073dc9ca46dcedbb 100644 (file)
@@ -57,6 +57,8 @@ import (
        "io/ioutil"
        "log"
        "os"
+       "path/filepath"
+       "runtime"
        "sort"
        "strconv"
        "strings"
@@ -66,8 +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")
-       sysRepo        = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo")
+       systemDLL      = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
 )
 
 func trim(s string) string {
@@ -596,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
@@ -613,12 +620,10 @@ func ParseFiles(fs []string) (*Source, error) {
        src := &Source{
                Funcs: make([]*Fn, 0),
                Files: make([]string, 0),
-               Imports: []string{
+               StdLibImports: []string{
                        "unsafe",
                },
-       }
-       if *systemDLL {
-               src.Import("internal/syscall/windows/sysdll")
+               ExternalImports: make([]string, 0),
        }
        for _, file := range fs {
                if err := src.ParseFile(file); err != nil {
@@ -689,10 +694,52 @@ 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 {
-       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
+       )
+       isStdRepo, err := src.IsStdRepo()
+       if err != nil {
+               return err
+       }
+       var pkgtype int
+       switch {
+       case isStdRepo:
+               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.ExternalImport("golang.org/x/sys/windows")
+               }
        }
        if packageName != "syscall" {
                src.Import("syscall")
@@ -702,22 +749,21 @@ 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))
-       err := t.Execute(w, src)
+       err = t.Execute(w, src)
        if err != nil {
                return errors.New("Failed to execute template: " + err.Error())
        }
@@ -770,7 +816,10 @@ const srcTemplate = `
 package {{packagename}}
 
 import (
-{{range .Imports}}"{{.}}"
+{{range .StdLibImports}}"{{.}}"
+{{end}}
+
+{{range .ExternalImports}}"{{.}}"
 {{end}}
 )
 
index fe8259b221e27fc9a0428dfb80ca341cdcf8d304..b364eeaba5dc0570ea3204bf5cc49fb5a967806f 100644 (file)
@@ -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 (file)
index 74d11f9..0000000
+++ /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<<uint(i)) != 0 {
-                       if s != "" {
-                               s += "|"
-                       }
-                       s += name
-               }
-       }
-       if s == "" {
-               return "<nil>"
-       }
-       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 "<nil>"
-       }
-       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
-}
index bb353b20111707171a63b99deefa860443f5db6f..b0636ed07ceef054655924339f6328db24c90a09 100644 (file)
@@ -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
index 78daf94deb4c414a53ae7aa4166bb8c102fb7cfd..b562400be8bdb7eb381a368488313cfafdcd44ce 100644 (file)
@@ -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
index fbfafbc10255216d0cad48851b52fa208b7528c6..2c2de7474a4415514c4a1f92c136801ef2925829 100644 (file)
@@ -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 (file)
index af2b67d..0000000
+++ /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))
-       }
-}
index d21e3fa32c49c92eb29d38d43fbaab8eb6be77d6..a10c8b65d9dbc2019d5f181c95e4c0d08a320f21 100644 (file)
@@ -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 (file)
index 19d5d8e..0000000
+++ /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))
-       }
-}
index 719396db53beb029a8a5b15c2f2b616f5d2802d3..fe173adda8879e194400d4d5ff7fc87c0c492810 100644 (file)
@@ -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
 }
index 796870825c98dc76d5768a8b11c453b049565e1a..b511867cda51d4cd13dee6ca7f4adabf8d048c32 100644 (file)
@@ -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++ {
index c7b4560b76bc5e8add239e8c8813168031805284..80544f331923d64f1383b73fef6e72947a05dd06 100644 (file)
@@ -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")
        }
index 23e7b5e420bac303ce0ffd03431d032db79d18bd..9c3ba5a81a051557a9bc0b1acf9940ee45a286bc 100644 (file)
@@ -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)
        }
index 6e63d9a0743fa903d994202d3edad202942db288..12f4782296c5e5b9b109dd5d6cac13cdd999b49c 100644 (file)
@@ -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)
        }
index f996a508f020a16c1414709eeaefab7ec5b9878e..ab5b4a97bab7ad27b74e81cfbd832d6953ded4a2 100644 (file)
@@ -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)
        }
index 88e09d3a14d211adf79c485cf855df68f2d5ffa4..85d27777ba7483f911771cc20171d127acac1579 100644 (file)
@@ -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)
        }
index 30f29e52a9f6fe0308c21ae1302d3f92bec3b08f..b9ed271486b8ca541986f56557fb7be2b7249300 100644 (file)
@@ -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)
        }
index 93059d1b5bbb10b5bdee80c14cc7381462687f62..12d1db0c86186ed8e651f8ccbbab642779faf610 100644 (file)
@@ -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)
        }
index 84096b07a59bffef0a3022c94eccb922b8a28897..78b7c07a0fa5912ea7c27581c85117bc74f976f4 100644 (file)
@@ -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)
        }
index e24c3b71cdad79bf47bd0da645cbc57c735f5117..61b52cd165fea987993507a604d4e15c1e2e4cda 100644 (file)
@@ -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)
        }
index 7aa75ab12df43dc3336aa4af0752a3115c47bcf6..52987ba9023702de92f3e4fa6eade6bd43b9cad0 100644 (file)
@@ -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)
        }
index 21f482b40fdf0e1ad19db7aa4ca8c9c0098c2d5a..5c59a0ded161acced089b3822c12fd2727b37622 100644 (file)
@@ -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)
        }
index df7df1e7e457eea2e2dca82d9a286b1e57c738bf..37bbd85de5c560fc739f116a7d34c797402fa472 100644 (file)
@@ -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)
        }
index 1d640700f7d6a86fbdb8566d31f3eee512dc9a21..0d831df1f67eb152bddbb1858ca583ef6a3fb3e1 100644 (file)
@@ -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)
        }
index d19036c72d1001ae0141eb78fccc972956dfcd63..8c1c5f4452c5c0c852d3ff1b33e5029b9d9d479d 100644 (file)
@@ -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)
                }
        }
 }
index 4bc8e3fc2e14796c8dd410603d52f3fc947aa441..798d41aa7d176b6e09fc93ac8f8e6454010bf1e3 100644 (file)
@@ -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 }
index 018ece2a5289ed8ae8fd9059096b71a0bc032d95..fe443592f87bed611c3957fde67fc56dcb295798 100644 (file)
@@ -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)
+       }
+}
index 2804550737429b23cd09a16584d458c84ff52579..2a24aaacfd72a031deb98832f89fcf99d1c0d099 100644 (file)
@@ -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, "", ""))
index 3a7a135a3c6842e6d5a7fc967ebd4d745e6bc1fe..657a7b731fabe6e2d7f5f99ddf5c836ec1784f3a 100644 (file)
 // 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) {
+//         // <setup code>
+//         t.Run("A=1", func(t *testing.T) { ... })
+//         t.Run("A=2", func(t *testing.T) { ... })
+//         t.Run("B=1", func(t *testing.T) { ... })
+//         // <tear-down code>
+//     }
+//
+// 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)
+//         })
+//         // <tear-down code>
+//     }
+//
 // Main
 //
 // It is sometimes necessary for a test program to do extra setup or teardown
@@ -196,13 +251,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 +407,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 +600,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
        }()
 
index 101145948fac436bdc002368e03176d59fd62be8..1d5d34a01526277502af3b34cb37ad6732519264 100644 (file)
@@ -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 :
 }
index a3da1fdabf445570a20f0006419daea83b45502e..e085f8a7d956bb2ee432254c4a8790c729d45bea 100644 (file)
@@ -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 = "<input>"
+       }
+       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 {
index 798bed7e92aa0aa0c17e53e81022d64e79f0a03d..3e92d659ca029e3d56c0236a589e8d82b52c2507 100644 (file)
@@ -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", "<input>:1:1", "illegal character NUL", 0)
+       testError(t, "\x80", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+       testError(t, "\xff", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+
+       testError(t, "a\x00", "<input>:1:2", "illegal character NUL", Ident)
+       testError(t, "ab\x80", "<input>:1:3", "illegal UTF-8 encoding", Ident)
+       testError(t, "abc\xff", "<input>:1:4", "illegal UTF-8 encoding", Ident)
+
+       testError(t, `"a`+"\x00", "<input>:1:3", "illegal character NUL", String)
+       testError(t, `"ab`+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+       testError(t, `"abc`+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+       testError(t, "`a"+"\x00", "<input>:1:3", "illegal character NUL", String)
+       testError(t, "`ab"+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+       testError(t, "`abc"+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+       testError(t, `'\"'`, "<input>:1:3", "illegal char escape", Char)
+       testError(t, `"\'"`, "<input>:1:3", "illegal char escape", String)
+
+       testError(t, `01238`, "<input>:1:6", "illegal octal number", Int)
+       testError(t, `01238123`, "<input>:1:9", "illegal octal number", Int)
+       testError(t, `0x`, "<input>:1:3", "illegal hexadecimal number", Int)
+       testError(t, `0xg`, "<input>:1:3", "illegal hexadecimal number", Int)
+       testError(t, `'aa'`, "<input>:1:4", "illegal char literal", Char)
+
+       testError(t, `'`, "<input>:1:2", "literal not terminated", Char)
+       testError(t, `'`+"\n", "<input>:1:2", "literal not terminated", Char)
+       testError(t, `"abc`, "<input>:1:5", "literal not terminated", String)
+       testError(t, `"abc`+"\n", "<input>:1:5", "literal not terminated", String)
+       testError(t, "`abc\n", "<input>:2:1", "literal not terminated", String)
+       testError(t, `/*/`, "<input>:1:4", "comment not terminated", EOF)
 }
 
 // An errReader returns (0, err) where err is not io.EOF.
index df8c95f8c8949e7ec05b5e68f54d486598c06dec..48e9aa7395cec9c4f9c6ec85350dc72d1100cbb2 100644 (file)
@@ -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.
 
index 22881c685279f6a94561e6c69867aedbe151f52e..8e5ad93ca6b5b881d87b73a6bbeaf808bd368904 100644 (file)
@@ -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}}
index bc2aa683ec9a0695f0f995e3a2a40545305f7b78..3ef065edcfdebefd07065d3ca56d3b9073a10240 100644 (file)
@@ -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 := "<nil>"
+       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)
+       }
+}
index c348366604e6dbe33b8910d4e2a86b4f077094a2..7661f7e54fc1302f8d1e1e5f2a1365127cbac8f8 100644 (file)
@@ -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
 }
index 8484729448eb96ec155e4942b8e69f8dcf8d050c..11365a791f7dfc48fd20b6affff042ae566fda37 100644 (file)
@@ -55,9 +55,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-       whence := 0
+       whence := seekStart
        if off < 0 {
-               whence = 2
+               whence = seekEnd
        }
        if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
                return err
index e592415daa5161bf0a5d36ca398b2ee774feabc1..91d54c9ffd0a9e947fa5b7367abeb2c10359d0c1 100644 (file)
@@ -55,9 +55,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-       whence := 0
+       whence := seekStart
        if off < 0 {
-               whence = 2
+               whence = seekEnd
        }
        if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
                return err
index de63b4bf4bb87be5b8c7b17f038a640358b31180..a4a068f78494c101f455dee014ca3faa2e44fb1b 100644 (file)
@@ -52,9 +52,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-       whence := 0
+       whence := seekStart
        if off < 0 {
-               whence = 2
+               whence = seekEnd
        }
        if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil {
                return err
index 51a1a2f66d87e31e6f55632a5533f10515284ac6..344a891d1a4eb15bd20706a2e6d3acffe3c537aa 100644 (file)
@@ -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
index 66777f6d736151a93320013aa6c0685b48653c95..19cd40d847729711297c86468c9f9b73e8fd3864 100644 (file)
@@ -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
index 0b7584ab9c2ffdc2927fe6a37506fcab05cea2c9..4b50dc509002f00877e67277dcd8331cc31170cc 100644 (file)
@@ -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)
+       }
+}
index c753119d5db76530d7aaf24a1dca95063f13c701..a6546f54b86ac79cb57f8dcee1e2885665e78644 100644 (file)
@@ -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++
index 6dc69f957990bb550cbc45ea63f299ff1a0f23db..4c7b17bfb14c0bfedf806571fc2f2e453377eef3 100644 (file)
@@ -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
index eb4b1f05cd046ddd1dfb08238c74b420d683dc9a..8850e3946770ea09203ddb3ea15d4c818e5eeea0 100644 (file)
@@ -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<<cbits - 1); cur&mask != mask {
+               // Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
+               return ErrInvalidHuffman
+       }
+
        return nil
 }
 
similarity index 73%
rename from src/net/http/lex.go
rename to src/vendor/golang.org/x/net/lex/httplex/httplex.go
index 63d14ec2ecca5bc089a41ced39477bdccf2dee4e..bd0ec24f444365fa73bb459dbd80f40397e8ad96 100644 (file)
@@ -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            = <any US-ASCII control character
 //                         (octets 0 - 31) and DEL (127)>
-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) {
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 986fda17dcd6e4a5073bc947bdea767240d43ad0..c4ace1991b35dc4baca17d6685116584fef05b6b 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-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)
                }
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 (file)
index 0000000..206a837
--- /dev/null
@@ -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 <length, prefix> 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<<i) == 0 {
+                       continue
+               }
+               if i <= sysRTAX_BRD {
+                       switch b[1] {
+                       case sysAF_LINK:
+                               a, err := parseLinkAddr(b)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               as[i] = a
+                               b = b[roundup(int(b[0])):]
+                       case sysAF_INET, sysAF_INET6:
+                               af = int(b[1])
+                               a, err := parseInetAddr(af, b)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               as[i] = a
+                               b = b[roundup(int(b[0])):]
+                       default:
+                               l, a, err := fn(af, b)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               as[i] = a
+                               ll := roundup(l)
+                               if len(b) < ll {
+                                       b = b[l:]
+                               } else {
+                                       b = b[ll:]
+                               }
+                       }
+               } else {
+                       a, err := parseDefaultAddr(b)
+                       if err != nil {
+                               return nil, err
+                       }
+                       as[i] = a
+                       b = b[roundup(int(b[0])):]
+               }
+       }
+       return as[:], nil
+}
diff --git a/src/vendor/golang.org/x/net/route/address_darwin_test.go b/src/vendor/golang.org/x/net/route/address_darwin_test.go
new file mode 100644 (file)
index 0000000..b86bd3d
--- /dev/null
@@ -0,0 +1,63 @@
+// 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 (
+       "reflect"
+       "testing"
+)
+
+type parseAddrsOnDarwinTest struct {
+       attrs uint
+       fn    func(int, []byte) (int, Addr, error)
+       b     []byte
+       as    []Addr
+}
+
+var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{
+       {
+               sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK,
+               parseKernelInetAddr,
+               []byte{
+                       0x10, 0x2, 0x0, 0x0, 0xc0, 0xa8, 0x56, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                       0x14, 0x12, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0,
+
+                       0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               },
+               []Addr{
+                       &Inet4Addr{IP: [4]byte{192, 168, 86, 0}},
+                       &LinkAddr{Index: 4},
+                       &Inet4Addr{IP: [4]byte{255, 255, 255, 255}},
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+               },
+       },
+}
+
+func TestParseAddrsOnDarwin(t *testing.T) {
+       tests := parseAddrsOnDarwinLittleEndianTests
+       if nativeEndian != littleEndian {
+               t.Skip("no test for non-little endian machine yet")
+       }
+
+       for i, tt := range tests {
+               as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+               if err != nil {
+                       t.Error(i, err)
+                       continue
+               }
+               if !reflect.DeepEqual(as, tt.as) {
+                       t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+                       continue
+               }
+       }
+}
diff --git a/src/vendor/golang.org/x/net/route/address_test.go b/src/vendor/golang.org/x/net/route/address_test.go
new file mode 100644 (file)
index 0000000..2005ef7
--- /dev/null
@@ -0,0 +1,103 @@
+// 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 (
+       "reflect"
+       "testing"
+)
+
+type parseAddrsTest struct {
+       attrs uint
+       fn    func(int, []byte) (int, Addr, error)
+       b     []byte
+       as    []Addr
+}
+
+var parseAddrsLittleEndianTests = []parseAddrsTest{
+       {
+               sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK | sysRTA_BRD,
+               parseKernelInetAddr,
+               []byte{
+                       0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                       0x38, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
+                       0x65, 0x6d, 0x31, 0x0, 0xc, 0x29, 0x66, 0x2c,
+                       0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                       0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xb4,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                       0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xff,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               },
+               []Addr{
+                       &LinkAddr{Index: 0},
+                       &LinkAddr{Index: 2, Name: "em1", Addr: []byte{0x00, 0x0c, 0x29, 0x66, 0x2c, 0xdc}},
+                       &Inet4Addr{IP: [4]byte{172, 16, 220, 180}},
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       &Inet4Addr{IP: [4]byte{172, 16, 220, 255}},
+               },
+       },
+       {
+               sysRTA_NETMASK | sysRTA_IFP | sysRTA_IFA,
+               parseKernelInetAddr,
+               []byte{
+                       0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+
+                       0x18, 0x12, 0xa, 0x0, 0x87, 0x8, 0x0, 0x0,
+                       0x76, 0x6c, 0x61, 0x6e, 0x35, 0x36, 0x38, 0x32,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                       0x10, 0x2, 0x0, 0x0, 0xa9, 0xfe, 0x0, 0x1,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               },
+               []Addr{
+                       nil,
+                       nil,
+                       &Inet4Addr{IP: [4]byte{255, 255, 255, 0}},
+                       nil,
+                       &LinkAddr{Index: 10, Name: "vlan5682"},
+                       &Inet4Addr{IP: [4]byte{169, 254, 0, 1}},
+                       nil,
+                       nil,
+               },
+       },
+}
+
+func TestParseAddrs(t *testing.T) {
+       tests := parseAddrsLittleEndianTests
+       if nativeEndian != littleEndian {
+               t.Skip("no test for non-little endian machine yet")
+       }
+
+       for i, tt := range tests {
+               as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+               if err != nil {
+                       t.Error(i, err)
+                       continue
+               }
+               as = as[:8] // the list varies between operating systems
+               if !reflect.DeepEqual(as, tt.as) {
+                       t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+                       continue
+               }
+       }
+}
diff --git a/src/vendor/golang.org/x/net/route/binary.go b/src/vendor/golang.org/x/net/route/binary.go
new file mode 100644 (file)
index 0000000..4c56163
--- /dev/null
@@ -0,0 +1,90 @@
+// 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
+
+// This file contains duplicates of encoding/binary package.
+//
+// This package is supposed to be used by the net package of standard
+// library. Therefore a package set used in the package must be the
+// same as net package.
+
+var (
+       littleEndian binaryLittleEndian
+       bigEndian    binaryBigEndian
+)
+
+type binaryByteOrder interface {
+       Uint16([]byte) uint16
+       Uint32([]byte) uint32
+       PutUint16([]byte, uint16)
+       PutUint32([]byte, uint32)
+       Uint64([]byte) uint64
+}
+
+type binaryLittleEndian struct{}
+
+func (binaryLittleEndian) Uint16(b []byte) uint16 {
+       _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func (binaryLittleEndian) PutUint16(b []byte, v uint16) {
+       _ = b[1] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v)
+       b[1] = byte(v >> 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 (file)
index 0000000..f452ad1
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+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 (file)
index 0000000..c737751
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+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 (file)
index 0000000..8f834e8
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+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 (file)
index 0000000..b18d85e
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+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 (file)
index 0000000..5df7a43
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+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 (file)
index 0000000..854906d
--- /dev/null
@@ -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 (file)
index 0000000..520d657
--- /dev/null
@@ -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 (file)
index 0000000..ac4e7a6
--- /dev/null
@@ -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 (file)
index 0000000..c830539
--- /dev/null
@@ -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 (file)
index 0000000..1e99a9c
--- /dev/null
@@ -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 (file)
index 0000000..24451d8
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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 (file)
index 0000000..27cbf6b
--- /dev/null
@@ -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 (file)
index 0000000..3fdd12d
--- /dev/null
@@ -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 (file)
index 0000000..6d03d00
--- /dev/null
@@ -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 (file)
index 0000000..a1263d8
--- /dev/null
@@ -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 (file)
index 0000000..c986e29
--- /dev/null
@@ -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 (file)
index 0000000..d333c6a
--- /dev/null
@@ -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 (file)
index 0000000..b07862f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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 (file)
index 0000000..99f57b7
--- /dev/null
@@ -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 := "<nil>"
+       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<<uint(i)) != 0 {
+                       if s != "" {
+                               s += "|"
+                       }
+                       s += name
+               }
+       }
+       if s == "" {
+               return "<nil>"
+       }
+       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 "<nil>"
+       }
+       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 = "<nil>"
+       }
+       lla := llAddr(a.Addr).String()
+       if lla == "" {
+               lla = "<nil>"
+       }
+       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 "<nil>"
+       }
+       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 (file)
index 0000000..80ca83a
--- /dev/null
@@ -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 (file)
index 0000000..fff3a0f
--- /dev/null
@@ -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 (file)
index 0000000..da848b3
--- /dev/null
@@ -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 (file)
index 0000000..7b05c1a
--- /dev/null
@@ -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 (file)
index 0000000..4d8076b
--- /dev/null
@@ -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 (file)
index 0000000..26d0438
--- /dev/null
@@ -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 (file)
index 0000000..d136325
--- /dev/null
@@ -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 (file)
index 0000000..fa6297f
--- /dev/null
@@ -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 (file)
index 0000000..265b81c
--- /dev/null
@@ -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 (file)
index 0000000..dd36dec
--- /dev/null
@@ -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 (file)
index 0000000..9bac2e3
--- /dev/null
@@ -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 (file)
index 0000000..b1920d7
--- /dev/null
@@ -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 (file)
index 0000000..a034d6f
--- /dev/null
@@ -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 (file)
index 0000000..aa4aad1
--- /dev/null
@@ -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 (file)
index 0000000..4fadc4e
--- /dev/null
@@ -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
+)
index a80a960394470b75c69eddf49982e4dd706e437a..81bf33c37a6df15fc511b64e50993507e038bcf4 100644 (file)
@@ -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
index 94cf9c68de0fe9bfb3bd6f79949fd57047a2a925..b18577c152849675078f6f8a4833c75e3507235e 100644 (file)
@@ -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"
 }
diff --git a/test/fixedbugs/issue14136.go b/test/fixedbugs/issue14136.go
new file mode 100644 (file)
index 0000000..928a60b
--- /dev/null
@@ -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"
+}
diff --git a/test/fixedbugs/issue15277.go b/test/fixedbugs/issue15277.go
new file mode 100644 (file)
index 0000000..719c9a4
--- /dev/null
@@ -0,0 +1,38 @@
+// 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.
+// +build amd64
+
+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)
+}
diff --git a/test/fixedbugs/issue15329.go b/test/fixedbugs/issue15329.go
new file mode 100644 (file)
index 0000000..30fbf13
--- /dev/null
@@ -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
+}
index ce6e3204b3ea2cf3e8787805d98f7b18f9e99010..6d3f3be53ec2a465c95096d0692c1df7ccf5724b 100644 (file)
@@ -5,6 +5,6 @@
 package c
 
 import (
-       _ "./a"
        _ "./b"
+       _ "./a"
 )
diff --git a/test/fixedbugs/issue15572.dir/a.go b/test/fixedbugs/issue15572.dir/a.go
new file mode 100644 (file)
index 0000000..1356601
--- /dev/null
@@ -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 (file)
index 0000000..355accc
--- /dev/null
@@ -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 (file)
index 0000000..cf77778
--- /dev/null
@@ -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
diff --git a/test/fixedbugs/issue15585.go b/test/fixedbugs/issue15585.go
new file mode 100644 (file)
index 0000000..79eb13f
--- /dev/null
@@ -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
+}
diff --git a/test/fixedbugs/issue15602.go b/test/fixedbugs/issue15602.go
new file mode 100644 (file)
index 0000000..badf813
--- /dev/null
@@ -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)
+}
diff --git a/test/fixedbugs/issue15604.go b/test/fixedbugs/issue15604.go
new file mode 100644 (file)
index 0000000..4dc0b0b
--- /dev/null
@@ -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 {
+               }
+       }
+}
diff --git a/test/fixedbugs/issue15646.dir/a.go b/test/fixedbugs/issue15646.dir/a.go
new file mode 100644 (file)
index 0000000..842f196
--- /dev/null
@@ -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 (file)
index 0000000..3d011ba
--- /dev/null
@@ -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 (file)
index 0000000..cd4ba9d
--- /dev/null
@@ -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
diff --git a/test/fixedbugs/issue15733.go b/test/fixedbugs/issue15733.go
new file mode 100644 (file)
index 0000000..8f609e6
--- /dev/null
@@ -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
+}
diff --git a/test/fixedbugs/issue15747.go b/test/fixedbugs/issue15747.go
new file mode 100644 (file)
index 0000000..34ec719
--- /dev/null
@@ -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 (file)
index 0000000..9620d3d
--- /dev/null
@@ -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
+}
diff --git a/test/fixedbugs/issue15838.dir/a.go b/test/fixedbugs/issue15838.dir/a.go
new file mode 100644 (file)
index 0000000..15b7f1d
--- /dev/null
@@ -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 (file)
index 0000000..9fd6efc
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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 (file)
index 0000000..fb1c64d
--- /dev/null
@@ -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
diff --git a/test/linkobj.go b/test/linkobj.go
new file mode 100644 (file)
index 0000000..8a86aa8
--- /dev/null
@@ -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...)
+}